﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Получает значение настройки плана обмена по ее имени.
// Для несуществующих настроек возвращается Неопределено.
// 
// Параметры:
//   ИмяПланаОбмена         - Строка - имя плана обмена из метаданных.
//   ИмяПараметра           - Строка - имя параметра плана обмена или список параметров, разделенных запятыми.
//                                     Список допустимых значений см. в функциях НастройкиПланаОбменаПоУмолчанию,
//                                     ОписаниеВариантаНастройкиОбменаПоУмолчанию.
//   ИдентификаторНастройки - Строка - имя предопределенной настройки плана обмена.
//   ВерсияКорреспондента   - Строка - версия конфигурации корреспондента.
// 
// Возвращаемое значение:
//   Произвольный, Структура - тип возвращаемого значения зависит от типа значения получаемой настройки.
//                             Произвольный, если в качестве ИмяПараметра был передан единичный параметр
//                             Структура, если в качестве параметра ИмяПараметра была передан список параметров через запятую.
//
Функция ЗначениеНастройкиПланаОбмена(ИмяПланаОбмена, ИмяПараметра, ИдентификаторНастройки = "", ВерсияКорреспондента = "") Экспорт
	
	ЗначениеПараметра = Новый Структура;
	НастройкиПланаОбмена = Неопределено;
	ОписаниеВариантаНастройки = Неопределено;
	ИмяПараметра = СтрЗаменить(ИмяПараметра, Символы.ПС, "");
	ИменаПараметров = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ИмяПараметра,,Истина);
	НастройкиПланаОбменаПоУмолчанию = НастройкиПланаОбменаПоУмолчанию(ИмяПланаОбмена);
	ОписаниеВариантаПоУмолчанию = ОписаниеВариантаНастройкиОбменаПоУмолчанию(ИмяПланаОбмена);
	Если ИменаПараметров.Количество() = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;
	Для Каждого ЕдиничныйПараметр Из ИменаПараметров Цикл
		ЗначениеЕдиничногоПараметра = Неопределено;
		Если НастройкиПланаОбменаПоУмолчанию.Свойство(ЕдиничныйПараметр) Тогда
			Если НастройкиПланаОбмена = Неопределено Тогда
				НастройкиПланаОбмена = ОбменДаннымиПовтИсп.НастройкиПланаОбмена(ИмяПланаОбмена);
			КонецЕсли;
			НастройкиПланаОбмена.Свойство(ЕдиничныйПараметр, ЗначениеЕдиничногоПараметра);
		ИначеЕсли ОписаниеВариантаПоУмолчанию.Свойство(ЕдиничныйПараметр) Тогда
			Если ОписаниеВариантаНастройки = Неопределено Тогда
				ОписаниеВариантаНастройки = ОбменДаннымиПовтИсп.ОписаниеВариантаНастройки(ИмяПланаОбмена, ИдентификаторНастройки, ВерсияКорреспондента);
			КонецЕсли;
			ОписаниеВариантаНастройки.Свойство(ЕдиничныйПараметр, ЗначениеЕдиничногоПараметра);
		КонецЕсли;
		Если ИменаПараметров.Количество() = 1 Тогда
			Возврат ЗначениеЕдиничногоПараметра;
		Иначе
			ЗначениеПараметра.Вставить(ЕдиничныйПараметр, ЗначениеЕдиничногоПараметра);
		КонецЕсли;
	КонецЦикла;
	Возврат ЗначениеПараметра;
	
КонецФункции

// Процедура-обработчик события "ПриСозданииНаСервере" для формы узла плана обмена.
//
// Параметры:
//  Форма - ФормаКлиентскогоПриложения - форма, из которой вызвана процедура:
//    * Объект - ДанныеФормыСтруктура:
//      ** Ссылка - ПланОбменаСсылка - узел плана обмена.
//  Отказ - Булево           - признак отказа от создания формы. Если установить в Истина, то форма создана не будет.
// 
Процедура ФормаУзлаПриСозданииНаСервере(Форма, Отказ) Экспорт
	
	ПредставлениеПланаОбмена = ЗначениеНастройкиПланаОбмена(
		Форма.Объект.Ссылка.Метаданные().Имя,
		"ЗаголовокУзлаПланаОбмена",
		ВариантОбменаДанными(Форма.Объект.Ссылка));
	
	Форма.АвтоЗаголовок = Ложь;
	Форма.Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Форма.Объект.Наименование + " (%1)",
		ПредставлениеПланаОбмена);
		
	Если ОбщегоНазначения.РазделениеВключено() 
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		
		МодульОбменДаннымиВнутренняяПубликация = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВнутренняяПубликация");
		МодульОбменДаннымиВнутренняяПубликация.ФормаУзлаПриСозданииНаСервере(Форма, Отказ);
		
	КонецЕсли;
	
	НастроитьЭлементыФормыЗацикливания(Форма);
	
КонецПроцедуры

// Процедура-обработчик события "ПриЗаписиНаСервере" для формы узла плана обмена.
//
// Параметры:
//  ТекущийОбъект - ПланОбменаОбъект - записываемый узел плана обмена.
//  Отказ         - Булево           - входящий, признак отказа от записи узла обмена.
//                                     Если установлен в Истина, то для узла не будет
//                                     зафиксировано завершение настройки синхронизации.
//
Процедура ФормаУзлаПриЗаписиНаСервере(ТекущийОбъект, Отказ) Экспорт
	
	Если Отказ Тогда
		Возврат;
	КонецЕсли;
	
	Если Не НастройкаСинхронизацииЗавершена(ТекущийОбъект.Ссылка) Тогда
		ЗавершитьНастройкуСинхронизацииДанных(ТекущийОбъект.Ссылка);
	КонецЕсли;
	
КонецПроцедуры

// Процедура-обработчик события "ПриСозданииНаСервере" для формы настройки узла.
//
// Параметры:
//  Форма          - ФормаКлиентскогоПриложения - форма, из которой вызвана процедура.
//  ИмяПланаОбмена - Строка           - имя плана обмена, для которого создана форма.
// 
Процедура ФормаНастройкиУзлаПриСозданииНаСервере(Форма, ИмяПланаОбмена) Экспорт
	
	ИдентификаторНастройки = "";
	
	Если Форма.Параметры.Свойство("ИдентификаторНастройки") Тогда
		ИдентификаторНастройки = Форма.Параметры.ИдентификаторНастройки;
	КонецЕсли;
	
	ПроверитьОбязательныеРеквизитыФормы(Форма, "НастройкаОтборовНаУзле, ВерсияКорреспондента");
	
	Форма.ВерсияКорреспондента   = Форма.Параметры.ВерсияКорреспондента;
	Форма.НастройкаОтборовНаУзле = НастройкаОтборовНаУзле(ИмяПланаОбмена, Форма.ВерсияКорреспондента, ИдентификаторНастройки);
	
	ФормаНастройкиУзлаОбработчикПриСозданииНаСервере(Форма, "НастройкаОтборовНаУзле");
	
КонецПроцедуры

// Определяет необходимость выполнения обработчика события "ПослеВыгрузкиДанных" при обмене в РИБ.
//
// Параметры:
//  Объект - ПланОбменаОбъект - узел плана обмена, для которого выполняется обработчик.
//  Ссылка - ПланОбменаСсылка - ссылка на узел плана обмена, для которого выполняется обработчик.
//
// Возвращаемое значение:
//   Булево - если Истина, то необходимо выполнить обработчик "ПослеВыгрузкиДанных"; Ложь - нет.
//
Функция НадоВыполнитьОбработчикПослеВыгрузкиДанных(Объект, Ссылка) Экспорт
	
	Возврат НадоВыполнитьОбработчик(Объект, Ссылка, "НомерОтправленного");
	
КонецФункции

// Определяет необходимость выполнения обработчика события "ПослеЗагрузкиДанных" при обмене в РИБ.
//
// Параметры:
//  Объект - ПланОбменаОбъект - узел плана обмена, для которого выполняется обработчик.
//  Ссылка - ПланОбменаСсылка - ссылка на узел плана обмена, для которого выполняется обработчик.
//
// Возвращаемое значение:
//   Булево - если Истина, то необходимо выполнить обработчик "ПослеЗагрузкиДанных"; Ложь - нет.
//
Функция НадоВыполнитьОбработчикПослеЗагрузкиДанных(Объект, Ссылка) Экспорт
	
	Возврат НадоВыполнитьОбработчик(Объект, Ссылка, "НомерПринятого");
	
КонецФункции

// Возвращает префикс этой информационной базы.
//
// Возвращаемое значение:
//   Строка - префикс этой информационной базы.
//
Функция ПрефиксИнформационнойБазы() Экспорт
	
	Возврат ПолучитьФункциональнуюОпцию("ПрефиксИнформационнойБазы");
	
КонецФункции

// Возвращает версию конфигурации корреспондента.
// Если версия конфигурации корреспондента не определена, то возвращает пустую версию - "0.0.0.0".
//
// Параметры:
//  Корреспондент - ПланОбменаСсылка - узел плана обмена, для которого необходимо получить версию конфигурации.
// 
// Возвращаемое значение:
//  Строка - версия конфигурации корреспондента.
//
// Пример:
//  Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбменДаннымиСервер.ВерсияКорреспондента(Корреспондент), "2.1.5.1")
//  >= 0 Тогда ...
//
Функция ВерсияКорреспондента(Знач Корреспондент) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ВерсияКорреспондента(Корреспондент);
КонецФункции

// Устанавливает префикс этой информационной базы.
//
// Параметры:
//   Префикс - Строка - новое значение префикса информационной базы.
//
Процедура УстановитьПрефиксИнформационнойБазы(Знач Префикс) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПрефиксацияОбъектов")
		И Не ОткрытьПомощникСозданияОбменаДаннымиДляНастройкиПодчиненногоУзла() Тогда
		
		МодульПрефиксацияОбъектовСлужебный = ОбщегоНазначения.ОбщийМодуль("ПрефиксацияОбъектовСлужебный");
		
		ПараметрыИзмененияПрефикса = Новый Структура("НовыйПрефиксИБ, ПродолжитьНумерацию",
			СокрЛП(Префикс), Истина);
		МодульПрефиксацияОбъектовСлужебный.ИзменитьПрефиксИБ(ПараметрыИзмененияПрефикса);
		
	Иначе
		// Изменение данных с целью перенумерации справочников и документов не должно выполняться 
		// - в случае, если подсистема префиксации не встроена,
		// - при первом запуске подчиненного узла РИБ.
		Константы.ПрефиксУзлаРаспределеннойИнформационнойБазы.Установить(СокрЛП(Префикс));
	КонецЕсли;
	
	ОбменДаннымиСлужебный.СброситьКэшМеханизмаРегистрацииОбъектов();
	
КонецПроцедуры

// Проверяет факт восстановления этой базы из резервной копии.
// Если база была восстановлена из резервной копии, то необходимо выполнить синхронизацию номеров отправленных и
// полученных сообщений для двух баз (номеру отправленного сообщения в этой базе присваивается значение номера
// принятого сообщения из базы-корреспондента).
// Если база была восстановлена из резервной копии, то рекомендуется не снимать с регистрации изменения данных на
// текущем узле, т.к. эти данные могли быть еще не отправлены.
//
// Параметры:
//   Отправитель    - ПланОбменаСсылка - узел, от имени которого было сформировано и отправлено сообщение обмена.
//   НомерПринятого - Число            - номер принятого сообщения в базе-корреспонденте.
//
// Возвращаемое значение:
//   ФиксированнаяСтруктура:
//     * Отправитель                 - ПланОбменаСсылка - см. выше параметр Отправитель.
//     * НомерПринятого              - Число            - см. выше параметр НомерПринятого.
//     * ВосстановленаРезервнаяКопия - Булево - Истина, если обнаружен факт восстановления этой базы из резервной копии.
//
Функция ПараметрыРезервнойКопии(Знач Отправитель, Знач НомерПринятого) Экспорт
	
	// Для базы, которая была поднята из резервной копии, номер отправленного сообщения
	// будет меньше номера принятого сообщения в корреспонденте.
	// Т.е. эта база получит номер принятого сообщения,
	// который она еще не отправляла - "сообщение из будущего".
	Результат = Новый Структура("Отправитель, НомерПринятого, ВосстановленаРезервнаяКопия");
	Результат.Отправитель = Отправитель;
	Результат.НомерПринятого = НомерПринятого;
	Результат.ВосстановленаРезервнаяКопия = (НомерПринятого > ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Отправитель, "НомерОтправленного"));
	
	Возврат Новый ФиксированнаяСтруктура(Результат);
КонецФункции

// Выполняет синхронизацию номеров отправленных и полученных сообщений
// для двух баз (номеру отправленного сообщения в этой базе присваивается значение номера принятого сообщения из
// базы-корреспондента).
//
// Параметры:
//   ПараметрыРезервнойКопии - ФиксированнаяСтруктура:
//     * Отправитель                 - ПланОбменаСсылка - узел, от имени которого было сформировано и отправлено
//                                                        сообщение обмена.
//     * НомерПринятого              - Число            - номер принятого сообщения в базе-корреспонденте.
//     * ВосстановленаРезервнаяКопия - Булево           - признак восстановления этой базы из резервной копии.
//
Процедура ПриВосстановленииРезервнойКопии(Знач ПараметрыРезервнойКопии) Экспорт
	
	Если ПараметрыРезервнойКопии.ВосстановленаРезервнаяКопия Тогда
		
		НачатьТранзакцию();
		Попытка
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(ПараметрыРезервнойКопии.Отправитель));
			ЭлементБлокировки.УстановитьЗначение("Ссылка", ПараметрыРезервнойКопии.Отправитель);
			Блокировка.Заблокировать();
			
			ЗаблокироватьДанныеДляРедактирования(ПараметрыРезервнойКопии.Отправитель);
			ОтправительОбъект = ПараметрыРезервнойКопии.Отправитель.ПолучитьОбъект();
			
			ОтправительОбъект.НомерОтправленного = ПараметрыРезервнойКопии.НомерПринятого;
			ОтправительОбъект.ОбменДанными.Загрузка = Истина;
			ОтправительОбъект.Записать();
			
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
		
	КонецЕсли;
	
КонецПроцедуры

// Возвращает идентификатор сохраненного варианта настройки плана обмена.
// Параметры:
//   УзелПланаОбмена         - ПланОбменаСсылка - узел плана обмена, для которого необходимо получить переопределяемое
//                                                имя.
//
// Возвращаемое значение:
//  Строка - идентификатор сохраненной настройки как он задан в конфигураторе.
//
Функция СохраненныйВариантНастройкиУзлаПланаОбмена(УзелПланаОбмена) Экспорт
	
	ВариантНастройки = "";
	
	Если ОбщегоНазначения.ЕстьРеквизитОбъекта("ВариантНастройки", УзелПланаОбмена.Метаданные()) Тогда
		
		УстановитьПривилегированныйРежим(Истина);
		ВариантНастройки = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(УзелПланаОбмена, "ВариантНастройки");
		
	КонецЕсли;
	
	Возврат ВариантНастройки;
	
КонецФункции

// Возвращает массив всех видов транспорта сообщений обмена, определенных в конфигурации.
//
// Возвращаемое значение:
//   Массив из ПеречислениеСсылка.ВидыТранспортаСообщенийОбмена - все виды транспорта сообщений обмена.
//
Функция ВсеТранспортыСообщенийОбменаКонфигурации() Экспорт
	
	Результат = Новый Массив;
	Результат.Добавить(Перечисления.ВидыТранспортаСообщенийОбмена.COM);
	Результат.Добавить(Перечисления.ВидыТранспортаСообщенийОбмена.WS);
	Результат.Добавить(Перечисления.ВидыТранспортаСообщенийОбмена.FILE);
	Результат.Добавить(Перечисления.ВидыТранспортаСообщенийОбмена.FTP);
	Результат.Добавить(Перечисления.ВидыТранспортаСообщенийОбмена.EMAIL);
	Результат.Добавить(Перечисления.ВидыТранспортаСообщенийОбмена.WSПассивныйРежим);
	
	Возврат Результат;
КонецФункции

// Выполняет отправку или получение данных для узла информационной базы используя любой из 
// доступных для плана обмена канал связи, кроме COM-соединения и web-сервиса.
//
// Параметры:
//  Отказ                        - Булево - флаг отказа, устанавливается в Истина в случае
//                                 не успешного выполнения процедуры.
//  УзелИнформационнойБазы       - УзелОбменаСсылка - ПланОбменаСсылка - узел плана обмена,
//                                 для которого выполняется действие обмена данными.
//  ДействиеПриОбмене            - ПеречислениеСсылка.ДействияПриОбмене - выполняемое действие обмена данными.
//  ВидТранспортаСообщенийОбмена - ПеречислениеСсылка.Перечисления.ВидыТранспортаСообщенийОбмена - вид транспорта,
//                                 который будет использоваться в процессе обмена данными. Если не указан, 
//                                 определяется из параметров транспорта, заданных для узла плана обмена при
//                                 настройке обмена. Необязательный, значение по умолчанию Неопределено.
//  ТолькоПараметры              - Булево - содержит признак выборочной загрузки данных при обмене РИБ.
//  ДополнительныеПараметры      - Структура - зарезервировано для служебного использования.
// 
Процедура ВыполнитьДействиеОбменаДляУзлаИнформационнойБазы(
		Отказ,
		УзелИнформационнойБазы,
		ДействиеПриОбмене,
		ВидТранспортаСообщенийОбмена = Неопределено,
		Знач ТолькоПараметры = Ложь,
		ДополнительныеПараметры = Неопределено) Экспорт
		
	Если ДополнительныеПараметры = Неопределено Тогда
		ДополнительныеПараметры = Новый Структура;
	КонецЕсли;
		
	УстановитьПривилегированныйРежим(Истина);
	
	// ИНИЦИАЛИЗАЦИЯ ОБМЕНА ДАННЫМИ
	СтруктураНастроекОбмена = НастройкиОбменаДляУзлаИнформационнойБазы(
		УзелИнформационнойБазы, ДействиеПриОбмене, ВидТранспортаСообщенийОбмена);
	ЗафиксироватьНачалоОбменаВРегистреСведений(СтруктураНастроекОбмена);
	
	Если СтруктураНастроекОбмена.Отказ Тогда
		
		// Если настройка содержит ошибки, то обмен не производим; статус "Отменено".
		ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
		
		Отказ = Истина;
		
		Возврат;
	КонецЕсли;
	
	Для Каждого Параметр Из ДополнительныеПараметры Цикл
		СтруктураНастроекОбмена.ДополнительныеПараметры.Вставить(Параметр.Ключ, Параметр.Значение);
	КонецЦикла;
	
	СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено;
	
	СтрокаСообщения = НСтр("ru = 'Начало процесса обмена данными для узла %1'", ОбщегоНазначения.КодОсновногоЯзыка());
	СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, СтруктураНастроекОбмена.УзелИнформационнойБазыНаименование);
	ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщения, СтруктураНастроекОбмена);
	
	// ОБМЕН ДАННЫМИ
	ВыполнитьОбменДаннымиЧерезФайловыйРесурс(СтруктураНастроекОбмена, ТолькоПараметры);
	
	ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
	
	Для Каждого Параметр Из СтруктураНастроекОбмена.ДополнительныеПараметры Цикл
		ДополнительныеПараметры.Вставить(Параметр.Ключ, Параметр.Значение);
	КонецЦикла;
	
	Если Не РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена) Тогда
		
		Отказ = Истина;
		
	КонецЕсли;
	
КонецПроцедуры

// Определяет, существует ли каталог на FTP-сервере.
//
// Параметры:
//  Путь - Строка - путь к каталогу.
//  ИмяКаталога - Строка - имя каталога.
//  FTPСоединение - FTPСоединение - FTPСоединение, используемое для подключения к FTP-серверу.
// 
// Возвращаемое значение:
//  Булево - если Истина, то каталог существует; Ложь - нет.
//
Функция FTPКаталогСуществует(Знач Путь, Знач ИмяКаталога, Знач FTPСоединение) Экспорт
	
	Для Каждого FTPФайл Из FTPСоединение.НайтиФайлы(Путь) Цикл
		
		Если FTPФайл.ЭтоКаталог() И FTPФайл.Имя = ИмяКаталога Тогда
			
			Возврат Истина;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Ложь;
КонецФункции

// Возвращает данные таблиц для реквизитов узла обмена.
// 
// Параметры:
//   Таблицы        - Массив из Строка - имена реквизитов узла плана обмена.
//   ИмяПланаОбмена - Строка - имя плана обмена.
// 
// Возвращаемое значение:
//   Соответствие - соответствие таблиц и их данных.
//
Функция ДанныеТаблицКорреспондента(Таблицы, Знач ИмяПланаОбмена) Экспорт
	
	Результат = Новый Соответствие;
	РеквизитыПланаОбмена = Метаданные.ПланыОбмена[ИмяПланаОбмена].Реквизиты;
	
	Для Каждого Элемент Из Таблицы Цикл
		
		Реквизит = РеквизитыПланаОбмена.Найти(Элемент);
		
		Если Реквизит <> Неопределено Тогда
			
			ТипыРеквизита = Реквизит.Тип.Типы();
			
			Если ТипыРеквизита.Количество() <> 1 Тогда
				
				СтрокаСообщения = НСтр("ru = 'Составной тип данных для значений по умолчанию не поддерживается.
					|Реквизит ""%1"".'");
				СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, Реквизит.ПолноеИмя());
				ВызватьИсключение СтрокаСообщения;
			КонецЕсли;
			
			ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипыРеквизита.Получить(0));
			
			Если Не ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных) Тогда
				
				СтрокаСообщения = НСтр("ru = 'Выбор значений по умолчанию поддерживается только для справочников.
					|Реквизит ""%1"".'");
				СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, Реквизит.ПолноеИмя());
				ВызватьИсключение СтрокаСообщения;
			КонецЕсли;
			
			ПолноеИмяОбъектаМетаданных = ОбъектМетаданных.ПолноеИмя();
			
			ДанныеТаблицы = Новый Структура("СвойстваОбъектаМетаданных, ТаблицаБазыКорреспондента");
			ДанныеТаблицы.СвойстваОбъектаМетаданных = СвойстваОбъектаМетаданных(ПолноеИмяОбъектаМетаданных);
			ДанныеТаблицы.ТаблицаБазыКорреспондента = ПолучитьОбъектыТаблицы(ПолноеИмяОбъектаМетаданных);
			
			Результат.Вставить(ПолноеИмяОбъектаМетаданных, ДанныеТаблицы);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Результат.Вставить("{ДополнительныеДанные}", Новый Структура); // Для обратной совместимости с 2.4.x
	
	Возврат Результат;
	
КонецФункции

// Выполняет установку в константе количества элементов в транзакции загрузки данных.
//
// Параметры:
//  Количество - Число - количество элементов в транзакции.
// 
Процедура УстановитьКоличествоЭлементовВТранзакцииЗагрузкиДанных(Количество) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	Константы.КоличествоЭлементовВТранзакцииЗагрузкиДанных.Установить(Количество);
	
КонецПроцедуры

// Возвращает представление даты синхронизации.
//
// Параметры:
//  ДатаСинхронизации - Дата - абсолютная дата синхронизации данных.
//
// Возвращаемое значение:
//  Строка - строковое представление даты.
//
Функция ПредставлениеДатыСинхронизации(Знач ДатаСинхронизации) Экспорт
	
	Если Не ЗначениеЗаполнено(ДатаСинхронизации) Тогда
		Возврат НСтр("ru = 'Синхронизация не выполнялась.'");
	КонецЕсли;
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Последняя синхронизация: %1'"), ОтносительнаяДатаСинхронизации(ДатаСинхронизации));
КонецФункции

// Возвращает представление относительной даты синхронизации.
//
// Параметры:
//  ДатаСинхронизации - Дата - абсолютная дата синхронизации данных.
//
// Возвращаемое значение:
//  Строка - представление относительной даты синхронизации:
//    *Никогда             (Т = пустая дата).
//    *Сейчас              (Т < 5 мин)
//    *5 минут назад       (5 мин  < Т < 15 мин)
//    *15 минут назад      (15 мин  < Т < 30 мин)
//    *30 минут назад      (30 мин  < Т < 1 час)
//    *1 час назад         (1 час  < Т < 2 час)
//    *2 часа назад        (2 час  < Т < 3 час).
//    *Сегодня, 12:44:12   (3 час  < Т < вчера).
//    *Вчера, 22:30:45     (вчера  < Т < позавчера).
//    *Позавчера, 21:22:54 (позавчера  < Т < поза-позавчера).
//    *<12 Марта 2012г.>   (поза-позавчера < Т).
//
Функция ОтносительнаяДатаСинхронизации(Знач ДатаСинхронизации) Экспорт
	
	Если Не ЗначениеЗаполнено(ДатаСинхронизации) Тогда
		
		Возврат НСтр("ru = 'Никогда'");
		
	КонецЕсли;
	
	ДатаТекущая = ТекущаяДатаСеанса();
	
	Интервал = ДатаТекущая - ДатаСинхронизации;
	
	Если Интервал < 0 Тогда // 0 мин
		
		Результат = Формат(ДатаСинхронизации, "ДЛФ=DD");
		
	ИначеЕсли Интервал < 60 * 5 Тогда // 5 мин
		
		Результат = НСтр("ru = 'Сейчас'");
		
	ИначеЕсли Интервал < 60 * 15 Тогда // 15 мин
		
		Результат = НСтр("ru = '5 минут назад'");
		
	ИначеЕсли Интервал < 60 * 30 Тогда // 30 мин
		
		Результат = НСтр("ru = '15 минут назад'");
		
	ИначеЕсли Интервал < 60 * 60 * 1 Тогда // 1 час
		
		Результат = НСтр("ru = '30 минут назад'");
		
	ИначеЕсли Интервал < 60 * 60 * 2 Тогда // 2 часа
		
		Результат = НСтр("ru = '1 час назад'");
		
	ИначеЕсли Интервал < 60 * 60 * 3 Тогда // 3 часа
		
		Результат = НСтр("ru = '2 часа назад'");
		
	Иначе
		
		КоличествоДнейРазницы = КоличествоДнейРазницы(ДатаСинхронизации, ДатаТекущая);
		
		Если КоличествоДнейРазницы = 0 Тогда // сегодня
			
			Результат = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Сегодня, %1'"), Формат(ДатаСинхронизации, "ДЛФ=T"));
			
		ИначеЕсли КоличествоДнейРазницы = 1 Тогда // вчера
			
			Результат = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Вчера, %1'"), Формат(ДатаСинхронизации, "ДЛФ=T"));
			
		ИначеЕсли КоличествоДнейРазницы = 2 Тогда // позавчера
			
			Результат = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Позавчера, %1'"), Формат(ДатаСинхронизации, "ДЛФ=T"));
			
		Иначе // давно
			
			Результат = Формат(ДатаСинхронизации, "ДЛФ=DD");
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

// Возвращает идентификатор поставляемого профиля групп доступа "Синхронизация данных с другими программами".
//
// Возвращаемое значение:
//  Строка - идентификатор поставляемого профиля групп доступа.
//
Функция ПрофильДоступаСинхронизацияДанныхСДругимиПрограммами() Экспорт
	
	Возврат "04937803-5dba-11df-a1d4-005056c00008";
	
КонецФункции

// Проверяет наличие возможности администрирования обменов у текущего пользователя.
//
// Возвращаемое значение:
//  Булево - если Истина - права есть, Ложь - прав нет.
//
Функция ЕстьПраваНаАдминистрированиеОбменов() Экспорт
	
	Возврат Пользователи.ЭтоПолноправныйПользователь();
	
КонецФункции

// Функция возвращает объект WSПрокси веб-сервиса Exchange, созданный с переданными параметрами.
//
// Параметры:
//  СтруктураНастроек - Структура:
//    * WSURLВебСервиса - Строка - месторасположение wsdl.
//    * WSИмяСервиса - Строка - имя сервиса.
//    * WSURLПространстваИменСервиса - Строка - URI пространства имен web-сервиса.
//    * WSИмяПользователя - Строка - имя пользователя для входа на сервер.
//    * WSПароль - Строка - пароль пользователя.
//    * WSТаймаут - Число - таймаут на операции выполняемые через полученное прокси.
//  СтрокаСообщенияОбОшибке - Строка - содержит подробное описание ошибки в случае неуспешного подключения;
//  СообщениеПользователю - Строка - содержит краткое описание ошибки в случае неуспешного подключения.
//
// Возвращаемое значение:
//  WSПрокси - объект WSПрокси веб-сервиса Exchange.
//
Функция ПолучитьWSПрокси(СтруктураНастроек, СтрокаСообщенияОбОшибке = "", СообщениеПользователю = "") Экспорт
	
	УдалитьНезначащиеСимволыВНастройкахПодключения(СтруктураНастроек);
	
	СтруктураНастроек.Вставить("WSURLПространстваИменСервиса", "http://www.1c.ru/SSL/Exchange");
	СтруктураНастроек.Вставить("WSИмяСервиса",                 "Exchange");
	СтруктураНастроек.Вставить("WSТаймаут", 600);
	
	Возврат ПолучитьWSПроксиПоПараметрамПодключения(СтруктураНастроек, СтрокаСообщенияОбОшибке, СообщениеПользователю);
КонецФункции

// Функция возвращает объект WSПрокси веб-сервиса Exchange_2_0_1_6, созданный с переданными параметрами.
//
// Параметры:
//  СтруктураНастроек - Структура:
//    * WSURLВебСервиса - Строка - месторасположение wsdl.
//    * WSИмяСервиса - Строка - имя сервиса.
//    * WSURLПространстваИменСервиса - Строка - URI пространства имен web-сервиса.
//    * WSИмяПользователя - Строка - имя пользователя для входа на сервер.
//    * WSПароль - Строка - пароль пользователя.
//    * WSТаймаут - Число - таймаут на операции выполняемые через полученное прокси.
//  СтрокаСообщенияОбОшибке - Строка - содержит подробное описание ошибки в случае неуспешного подключения;
//  СообщениеПользователю - Строка - содержит краткое описание ошибки в случае неуспешного подключения.
//
// Возвращаемое значение:
//  WSПрокси - объект WSПрокси веб-сервиса Exchange_2_0_1_6.
//
Функция ПолучитьWSПрокси_2_0_1_6(СтруктураНастроек, СтрокаСообщенияОбОшибке = "", СообщениеПользователю = "") Экспорт
	
	УдалитьНезначащиеСимволыВНастройкахПодключения(СтруктураНастроек);
	
	СтруктураНастроек.Вставить("WSURLПространстваИменСервиса", "http://www.1c.ru/SSL/Exchange_2_0_1_6");
	СтруктураНастроек.Вставить("WSИмяСервиса",                 "Exchange_2_0_1_6");
	СтруктураНастроек.Вставить("WSТаймаут", 600);
	
	Возврат ПолучитьWSПроксиПоПараметрамПодключения(СтруктураНастроек, СтрокаСообщенияОбОшибке, СообщениеПользователю);
КонецФункции

// Функция возвращает объект WSПрокси веб-сервиса Exchange_2_0_1_7, созданный с переданными параметрами.
//
// Параметры:
//  СтруктураНастроек - Структура:
//    * WSURLВебСервиса - Строка - месторасположение wsdl.
//    * WSИмяСервиса - Строка - имя сервиса.
//    * WSURLПространстваИменСервиса - Строка - URI пространства имен web-сервиса.
//    * WSИмяПользователя - Строка - имя пользователя для входа на сервер.
//    * WSПароль - Строка - пароль пользователя.
//    * WSТаймаут - Число - таймаут на операции выполняемые через полученное прокси.
//  СтрокаСообщенияОбОшибке - Строка - содержит подробное описание ошибки в случае неуспешного подключения;
//  СообщениеПользователю - Строка - содержит краткое описание ошибки в случае неуспешного подключения.
//  Таймаут - Число - таймаут. 
//
// Возвращаемое значение:
//  WSПрокси - объект WSПрокси веб-сервиса Exchange_2_0_1_7.
//
Функция ПолучитьWSПрокси_2_1_1_7(СтруктураНастроек, СтрокаСообщенияОбОшибке = "", СообщениеПользователю = "", Таймаут = 600) Экспорт
	
	УдалитьНезначащиеСимволыВНастройкахПодключения(СтруктураНастроек);
	
	СтруктураНастроек.Вставить("WSURLПространстваИменСервиса", "http://www.1c.ru/SSL/Exchange_2_0_1_6");
	СтруктураНастроек.Вставить("WSИмяСервиса",                 "Exchange_2_0_1_6");
	СтруктураНастроек.Вставить("WSТаймаут", Таймаут);
	
	Возврат ПолучитьWSПроксиПоПараметрамПодключения(СтруктураНастроек, СтрокаСообщенияОбОшибке, СообщениеПользователю, Истина);
КонецФункции

// Функция возвращает объект WSПрокси веб-сервиса Exchange_3_0_1_1, созданный с переданными параметрами.
//
// Параметры:
//  СтруктураНастроек - Структура:
//    * WSURLВебСервиса - Строка - месторасположение wsdl.
//    * WSИмяСервиса - Строка - имя сервиса.
//    * WSURLПространстваИменСервиса - Строка - URI пространства имен web-сервиса.
//    * WSИмяПользователя - Строка - имя пользователя для входа на сервер.
//    * WSПароль - Строка - пароль пользователя.
//    * WSТаймаут - Число - таймаут на операции выполняемые через полученное прокси.
//  СтрокаСообщенияОбОшибке - Строка - содержит подробное описание ошибки в случае неуспешного подключения;
//  СообщениеПользователю - Строка - содержит краткое описание ошибки в случае неуспешного подключения.
//  Таймаут - Число - таймаут. 
//
// Возвращаемое значение:
//  WSПрокси - объект WSПрокси веб-сервиса Exchange_3_0_1_1.
//
Функция ПолучитьWSПрокси_3_0_1_1(СтруктураНастроек, СтрокаСообщенияОбОшибке = "", СообщениеПользователю = "", Таймаут = 600) Экспорт
	
	УдалитьНезначащиеСимволыВНастройкахПодключения(СтруктураНастроек);
	
	СтруктураНастроек.Вставить("WSURLПространстваИменСервиса", "http://www.1c.ru/SSL/Exchange_3_0_1_1");
	СтруктураНастроек.Вставить("WSИмяСервиса",                 "Exchange_3_0_1_1");
	СтруктураНастроек.Вставить("WSТаймаут",                    Таймаут);
	
	Возврат ПолучитьWSПроксиПоПараметрамПодключения(СтруктураНастроек, СтрокаСообщенияОбОшибке, СообщениеПользователю, Истина);
	
КонецФункции

// Функция возвращает объект WSПрокси веб-сервиса Exchange_3_0_1_1, созданный с переданными параметрами.
//
// Параметры:
//  СтруктураНастроек - Структура:
//    * WSURLВебСервиса - Строка - месторасположение wsdl.
//    * WSИмяСервиса - Строка - имя сервиса.
//    * WSURLПространстваИменСервиса - Строка - URI пространства имен web-сервиса.
//    * WSИмяПользователя - Строка - имя пользователя для входа на сервер.
//    * WSПароль - Строка - пароль пользователя.
//    * WSТаймаут - Число - таймаут на операции выполняемые через полученное прокси.
//  СтрокаСообщенияОбОшибке - Строка - содержит подробное описание ошибки в случае неуспешного подключения;
//  СообщениеПользователю - Строка - содержит краткое описание ошибки в случае неуспешного подключения.
//  Таймаут - Число - таймаут. 
//
// Возвращаемое значение:
//  WSПрокси - объект WSПрокси веб-сервиса Exchange_3_0_2_1.
//
Функция ПолучитьWSПрокси_3_0_2_1(СтруктураНастроек, СтрокаСообщенияОбОшибке = "", СообщениеПользователю = "", Таймаут = 600) Экспорт
	
	УдалитьНезначащиеСимволыВНастройкахПодключения(СтруктураНастроек);
	
	СтруктураНастроек.Вставить("WSURLПространстваИменСервиса", "http://www.1c.ru/SSL/Exchange_3_0_2_1");
	СтруктураНастроек.Вставить("WSИмяСервиса",                 "Exchange_3_0_2_1");
	СтруктураНастроек.Вставить("WSТаймаут",                    Таймаут);
	
	Возврат ПолучитьWSПроксиПоПараметрамПодключения(СтруктураНастроек, СтрокаСообщенияОбОшибке, СообщениеПользователю, Истина);
	
КонецФункции

// Функция возвращает объект WSПрокси веб-сервиса Exchange_3_0_1_1, созданный с переданными параметрами.
//
// Параметры:
//  СтруктураНастроек - Структура:
//    * WSURLВебСервиса - Строка - месторасположение wsdl.
//    * WSИмяСервиса - Строка - имя сервиса.
//    * WSURLПространстваИменСервиса - Строка - URI пространства имен web-сервиса.
//    * WSИмяПользователя - Строка - имя пользователя для входа на сервер.
//    * WSПароль - Строка - пароль пользователя.
//    * WSТаймаут - Число - таймаут на операции выполняемые через полученное прокси.
//  СтрокаСообщенияОбОшибке - Строка - содержит подробное описание ошибки в случае неуспешного подключения;
//  СообщениеПользователю - Строка - содержит краткое описание ошибки в случае неуспешного подключения.
//  Таймаут - Число - таймаут. 
//
// Возвращаемое значение:
//  WSПрокси - объект WSПрокси веб-сервиса Exchange_3_0_2_1.
//
Функция ПолучитьWSПрокси_3_0_2_2(СтруктураНастроек, СтрокаСообщенияОбОшибке = "", СообщениеПользователю = "", Таймаут = 600) Экспорт
	
	УдалитьНезначащиеСимволыВНастройкахПодключения(СтруктураНастроек);
	
	СтруктураНастроек.Вставить("WSURLПространстваИменСервиса", "http://www.1c.ru/SSL/Exchange_3_0_2_2");
	СтруктураНастроек.Вставить("WSИмяСервиса",                 "Exchange_3_0_2_2");
	СтруктураНастроек.Вставить("WSТаймаут",                    Таймаут);
	
	Возврат ПолучитьWSПроксиПоПараметрамПодключения(СтруктураНастроек, СтрокаСообщенияОбОшибке, СообщениеПользователю, Истина);
	
КонецФункции

// Возвращает допустимое количество элементов, обрабатываемых в одной транзакции загрузки данных.
//
// Возвращаемое значение:
//   Число - допустимое количество элементов, обрабатываемых в одной транзакции загрузки данных.
// 
Функция КоличествоЭлементовВТранзакцииЗагрузкиДанных() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	Возврат Константы.КоличествоЭлементовВТранзакцииЗагрузкиДанных.Получить();
	
КонецФункции

// Возвращает допустимое количество элементов, обрабатываемых в одной транзакции выгрузки данных.
//
// Возвращаемое значение:
//   Число - допустимое количество элементов, обрабатываемых в одной транзакции выгрузки данных.
// 
Функция КоличествоЭлементовВТранзакцииВыгрузкиДанных() Экспорт
	
	Возврат 1;
	
КонецФункции

// Возвращает таблицу с данными узлов всех настроенных обменов БСП.
//
// Возвращаемое значение:
//   ТаблицаЗначений:
//     * УзелИнформационнойБазы - ПланОбменаСсылка - ссылка на узел плана обмена.
//     * Наименование - Строка - наименование узла плана обмена.
//     * ИмяПланаОбмена - Строка - имя плана обмена.
//
Функция УзлыОбменаБСП() Экспорт
	
	Запрос = Новый Запрос(ТекстЗапросаПланыОбменаДляМонитора());
	УстановитьПривилегированныйРежим(Истина);
	УзлыОбменаБСП = Запрос.Выполнить().Выгрузить();
	УстановитьПривилегированныйРежим(Ложь);
	
	Возврат УзлыОбменаБСП;
	
КонецФункции

// Определяет, используются ли типовых правила конвертации для плана обмена.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого загружаются правила.
//
// Возвращаемое значение:
//   Булево - если Истина, то используются; Ложь - нет.
//
Функция ИспользуютсяТиповыеПравила(ИмяПланаОбмена) Экспорт
	
	Возврат РегистрыСведений.ПравилаДляОбменаДанными.ИспользуютсяТиповыеПравила(ИмяПланаОбмена);
	
КонецФункции

// Устанавливает внешнее соединение с информационной базой и возвращает описание соединения.
//
// Параметры:
//  Параметры - Структура - параметры для установки внешнего соединения с информационной базой.
//                          Свойства см. в функции
//                          ОбщегоНазначенияКлиентСервер.СтруктураПараметровДляУстановкиВнешнегоСоединения:
//
//    * ВариантРаботыИнформационнойБазы             - Число  -  вариант работы информационной базы: 0 - файловый; 1 -
//	                                                           клиент-серверный;
//    * КаталогИнформационнойБазы                   - Строка - каталог информационной базы для файлового режима работы;
//    * ИмяСервера1СПредприятия                     - Строка - имя сервера1С:Предприятия;
//    * ИмяИнформационнойБазыНаСервере1СПредприятия - Строка - имя информационной базы на сервере1С:Предприятия;
//    * АутентификацияОперационнойСистемы           - Булево - признак аутентификации операционной системы при создании
//	                                                           внешнего подключения к информационной базе;
//    * ИмяПользователя                             - Строка - имя пользователя информационной базы;
//    * ПарольПользователя                          - Строка - пароль пользователя информационной базы.
//
// Возвращаемое значение:
//  Структура:
//    * Соединение                  - COMОбъект
//                                  - Неопределено - указатель на COM-объект соединения или Неопределено в
//                                    случае ошибки;
//    * КраткоеОписаниеОшибки       - Строка - краткое описание ошибки;
//    * ПодробноеОписаниеОшибки     - Строка - подробное описание ошибки;
//    * ОшибкаПодключенияКомпоненты - Булево - флаг ошибки подключения COM.
//
Функция ВнешнееСоединениеСБазой(Параметры) Экспорт
	
	// Преобразуем настройки - параметры внешнего соединения в параметры транспорта.
	НастройкиТранспорта = НастройкиТранспортаПоПараметрамВнешнегоСоединения(Параметры);
	Возврат УстановитьВнешнееСоединениеСБазой(НастройкиТранспорта);
	
КонецФункции

// Точка входа для выполнения итерации обмена данными (загрузки и выгрузки) с внешней системой по узлу плана обмена.
//
// Параметры:
//  Корреспондент - ПланОбменаСсылка - узел плана обмена, соответствующий внешней системе.
//  ПараметрыОбмена - Структура - должна содержать следующие параметры:
//    * ВыполнятьЗагрузку - Булево - флаг необходимости выполнять загрузку данных.
//    * ВыполнятьОтправкуНастроек - Булево - флаг необходимости выполнять отправку настроек XDTO.
//  ФлагОшибка - Булево - Истина, в случае возникновения ошибки при выполнении обмена.
//                        Подробная информация об ошибке фиксируется в журнале регистрации.
// 
Процедура ВыполнитьОбменДаннымиСВнешнейСистемой(Корреспондент, ПараметрыОбмена, ФлагОшибка) Экспорт
	
	ДополнительныеПараметры = Новый Структура;
		
	ДействиеЗагрузка = Перечисления.ДействияПриОбмене.ЗагрузкаДанных;
	ДействиеВыгрузка = Перечисления.ДействияПриОбмене.ВыгрузкаДанных;
	
	Отказ = Ложь;

	ПередВыполнениемОбменов(Корреспондент, Отказ);
	Если Отказ = Истина Тогда
		
		Возврат;
		
	КонецЕсли;
	
	ТолькоПараметры = Ложь;
	ВидТранспортаСообщенийОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.ВнешняяСистема;
	
	ФлагОшибка = Ложь;
	
	Если ПараметрыОбмена.ВыполнятьЗагрузку Тогда
		
		ВыполнитьДействиеОбменаДляУзлаИнформационнойБазы(ФлагОшибка, Корреспондент,
			ДействиеЗагрузка, ВидТранспортаСообщенийОбмена, ТолькоПараметры, ДополнительныеПараметры);
			
	КонецЕсли;
	
	Если ПараметрыОбмена.ВыполнятьОтправкуНастроек Тогда
		
		ВыполнитьДействиеОбменаДляУзлаИнформационнойБазы(ФлагОшибка, Корреспондент,
			ДействиеВыгрузка, ВидТранспортаСообщенийОбмена, ТолькоПараметры, ДополнительныеПараметры);
			
	КонецЕсли;
	
	ПослеВыполненияОбменов(Корреспондент, Отказ);
	
КонецПроцедуры

// Определяет настройки по умолчанию для плана обмена, которые затем могут быть переопределены
// в модуле менеджера плана обмена в процедуре ПриПолученииНастроек().
// 
// Параметры:
//   ИмяПланаОбмена         - Строка - имя плана обмена из метаданных.
//   
// Возвращаемое значение:
//   Структура:
//      * ВариантыНастроекОбмена                 - см. КоллекцияВариантовНастроекОбмена
//      * ВидГруппыДляВариантовНастроек          - ВидГруппыФормы - вариант вида группы для отображения в
//                                                 дереве команд создания обмена вариантов настроек.
//      * ИмяКонфигурацииИсточника               - Строка - имя конфигурации источника, выводимое в
//                                                 пользовательском интерфейсе.
//      * ИмяКонфигурацииПриемника               - Структура - перечень идентификаторов конфигураций-корреспондентов,
//                                                 обмен с которыми возможен через данный план обмена.
//      * ВерсииФорматаОбмена                    - Соответствие из КлючИЗначение - номеров поддерживаемых версий формата
//                                                 и ссылок на общие модули с логикой обмена через формат.
//                                                 Используется только для обменов через универсальный формат:
//         ** Ключ - Число - версия формата.
//         ** Значение - ОбщийМодуль - ссылка на общий модуль.
//      * ФорматОбмена                             - Строка - пространство имен XDTO пакета, в котором содержится 
//                                                   универсальный формат, без указания версии формата.
//                                                   Используется только для обменов через универсальный формат.
//      * РасширенияФорматаОбмена                  - Соответствие из КлючИЗначение:
//        ** Ключ                                  - Строка - URI пространства имен схемы расширения формата.
//        ** Значение                              - Строка - номер расширяемой версии формата.
//      * ПланОбменаИспользуетсяВМоделиСервиса     - Булево - признак использования плана обмена для организации
//                                                   обмена в модели сервиса.
//      * ЭтоПланОбменаXDTO                        - Булево - признак того, что это план обмена через
//                                                   универсальный формат.
//      * ПредупреждатьОНесоответствииВерсийПравилОбмена - Булево - признак необходимости проверки на
//                                                                  расхождение версий в правилах конвертации.
//                                                                  Проверка выполняется при загрузке комплекта
//                                                                  правил, при отправке данных и при получении данных.
//      * ИмяПланаОбменаДляПереходаНаНовыйОбмен    - Строка - если для плана обмена свойство установлено, в 
//                                                   рабочих местах управления настройками не будет 
//                                                   предлагаться настроить этот вид обмена.
//                                                   Существующие обмены этого вида будут продолжать
//                                                   отображаться в списке настроенных обменов.
//                                                   Получении сообщения обмена в новом формате будет
//                                                   инициировать переход на новый вид обмена.
//      * НазначениеПланаОбмена                    - Строка - вариант назначения плана обмена.
//      * Алгоритмы                                - Структура - перечень экспортных процедур и функций, которые
//                                                   объявлены в модуле менеджера плана обмена
//                                                   и используются подсистемой обмена данными.
//      *ПравилаРегистрацииВМенеджере              - Булево - признак использования правил регистрации, 
//                                                   расположенных в общем модуле (менеджере регистрации)
//      *ИмяМенеджераРегистрации                   - Строка - имя модуля с правилами регистрации
//      *ИспользоватьКешПубличныхИдентификаторов   - Булево - признак того, что при загрузке данных будет
//                                                   использован кеш для поиска ссылок
//      *Глобальный                                - Булево - если установлено Истина, то план обмена может быть 
//                                                   использован для обмена с планами обмена с другими наименованиями.
//                                                   Только для обмена через EnterpriseData
//
Функция НастройкиПланаОбменаПоУмолчанию(ИмяПланаОбмена) Экспорт
	
	НазначениеПланаОбмена = "СинхронизацияСДругойПрограммой";
	Если ОбменДаннымиПовтИсп.ЭтоПланОбменаРаспределеннойИнформационнойБазы(ИмяПланаОбмена) Тогда
		НазначениеПланаОбмена = "РИБ";
	КонецЕсли;
	
	Алгоритмы = Новый Структура;
	Алгоритмы.Вставить("ПриПолученииВариантовНастроекОбмена",          Ложь);
	Алгоритмы.Вставить("ПриПолученииОписанияВариантаНастройки",        Ложь);
	
	Алгоритмы.Вставить("ОписаниеОграниченийПередачиДанных",            Ложь);
	Алгоритмы.Вставить("ОписаниеЗначенийПоУмолчанию",                  Ложь);
	
	Алгоритмы.Вставить("ПредставлениеОтбораИнтерактивнойВыгрузки",     Ложь);
	Алгоритмы.Вставить("НастроитьИнтерактивнуюВыгрузку",               Ложь);
	Алгоритмы.Вставить("НастроитьИнтерактивнуюВыгрузкуВМоделиСервиса", Ложь);
	
	Алгоритмы.Вставить("ОбработчикПроверкиОграниченийПередачиДанных",  Ложь);
	Алгоритмы.Вставить("ОбработчикПроверкиЗначенийПоУмолчанию",        Ложь);
	Алгоритмы.Вставить("ОбработчикПроверкиПараметровУчета",            Ложь);
	
	Алгоритмы.Вставить("ПриПодключенииККорреспонденту",                Ложь);
	Алгоритмы.Вставить("ПриПолученииДанныхОтправителя",                Ложь);
	Алгоритмы.Вставить("ПриОтправкеДанныхОтправителя",                 Ложь);
	
	Алгоритмы.Вставить("ПриСохраненииНастроекСинхронизацииДанных",     Ложь);
	
	Алгоритмы.Вставить("ПриОпределенииПоддерживаемыхОбъектовФормата",  Ложь);
	Алгоритмы.Вставить("ПриОпределенииПоддерживаемыхКорреспондентомОбъектовФормата", Ложь);
	
	Алгоритмы.Вставить("ПередНастройкойСинхронизацииДанных",           Ложь);
	
	Параметры = Новый Структура;
	Параметры.Вставить("ВариантыНастроекОбмена",                         КоллекцияВариантовНастроекОбмена());
	Параметры.Вставить("ИмяКонфигурацииИсточника",                       "");
	Параметры.Вставить("ИмяКонфигурацииПриемника",                       Новый Структура);
	Параметры.Вставить("ВерсииФорматаОбмена",                            Новый Соответствие);
	Параметры.Вставить("ФорматОбмена",                                   "");
	Параметры.Вставить("РасширенияФорматаОбмена",                        Новый Соответствие);
	Параметры.Вставить("ПланОбменаИспользуетсяВМоделиСервиса",           Ложь);
	Параметры.Вставить("ЭтоПланОбменаXDTO",                              Ложь);
	Параметры.Вставить("ИмяПланаОбменаДляПереходаНаНовыйОбмен",          "");
	Параметры.Вставить("ПредупреждатьОНесоответствииВерсийПравилОбмена", Истина);
	Параметры.Вставить("НазначениеПланаОбмена",                          НазначениеПланаОбмена);
	Параметры.Вставить("НаличиеПравилКонвертацииОбязательно",            Истина);
	Параметры.Вставить("РежимВыборочнойРегистрации",                     Неопределено);
	Параметры.Вставить("Алгоритмы",                                      Алгоритмы);
	Параметры.Вставить("ПравилаРегистрацииВМенеджере", Ложь);
	Параметры.Вставить("ИмяМенеджераРегистрации", "");
	Параметры.Вставить("ИспользоватьКешПубличныхИдентификаторов", Ложь);
	Параметры.Вставить("Глобальный", Ложь);
		
	Возврат Параметры;
	
КонецФункции

// Определяет настройки по умолчанию варианта настройки обмена, которые затем могут быть переопределены
// в модуле менеджера плана обмена в процедуре ПриПолученииОписанияВариантаНастройки().
//
// Параметры:
//   ИмяПланаОбмена - Строка - содержит имя плана обмена.
// 
// Возвращаемое значение:
//   Структура:
//      * Отборы                                    - Структура - отборы на узле плана обмена, 
//                                                    подлежат заполнению значениями по умолчанию.
//      * ЗначенияПоУмолчанию                       - Структура - значения по умолчанию на узле плана обмена. 
//      * ОбщиеДанныеУзлов                          - Строка - имена реквизитов и табличных частей плана обмена, 
//                                                    через запятую, которые являются общими для пары 
//                                                    обменивающихся конфигураций. 
//      * ИспользоватьПомощникСозданияОбменаДанными - Булево - признак, будет ли использоваться помощник для
//                                                    создания новых узлов плана обмена.
//      * ИмяФормыСозданияНачальногоОбраза          - Строка - имя используемой формы создания начального
//                                                    образа распределенной ИБ.
//      * ИмяФормыПомощникаНастройкиСинхронизацииДанных - Строка - имя формы, которая будет использована для настройки
//                                                        правил отправки и получения данных вместо
//                                                        стандартной формы.
//      * ПояснениеДляНастройкиПараметровУчета      - Строка - пояснение о последовательности действий пользователя 
//                                                    для настройки параметров учета в текущей
//                                                    информационной базе.
//      * ПутьКФайлуКомплектаПравилНаПользовательскомСайте - Строка - путь к файлу комплекта правил в виде архива
//                                                           на пользовательском сайте в разделе конфигурации.
//      * ПутьКФайлуКомплектаПравилВКаталогеШаблонов - Строка - относительный путь к файлу комплекта правил в
//                                                     каталоге шаблонов.
//      * ЗаголовокКомандыДляСозданияНовогоОбменаДанными - Строка - представление команды, выводимое в пользовательском 
//                                                         интерфейсе при создании новой настройки
//                                                                         обмена данными.
//      * ЗаголовокПомощникаСозданияОбмена          - Строка - представление заголовка формы помощника
//                                                    создания обмена данными выводимое в
//                                                    пользовательском интерфейсе.
//      * ЗаголовокУзлаПланаОбмена                  - Строка - представление узла плана обмена
//                                                    выводимое в пользовательском интерфейсе.
//      * ИмяКонфигурацииКорреспондента             - Строка - идентификатор конфигурации корреспондента.
//      * НаименованиеКонфигурацииКорреспондента    - Строка - представление наименования конфигурации корреспондента  
//                                                    выводимое в пользовательском интерфейсе.
//      * ИспользуемыеТранспортыСообщенийОбмена     - Массив из ПеречислениеСсылка.ВидыТранспортаСообщенийОбмена 
//                                                    - перечень используемых транспортов сообщений. Если не заполнен, 
//                                                    будут доступны все возможные виды транспорта.
//      * КраткаяИнформацияПоОбмену                 - Строка - краткое описание обмена данными, которое
//                                                    выводится на первой странице помощника
//                                                    создания обмена.
//      * ПодробнаяИнформацияПоОбмену               - Строка - ссылка на веб-страницу или полный путь к
//                                                    форме внутри конфигурации строкой, для
//                                                    отображения в помощнике создания обмена.
//      * ИмяФайлаНастроекДляПриемника              - Строка - имя файла для сохранения настроек подключения
//                                                    при настройке обмена через offline-каналы.
//      * ПоддерживаетсяСопоставлениеДанных         - Булево - Истина, если для данного варианта настройки 
//                                                    поддерживается
//                                                    интерактивное сопоставление данных. В
//                                                    противном случае полученные сообщения обмена
//                                                    будут сразу загружаться в информационную базу.
//      * РасширениеФормата                         - Строка - имя расширения формата, применимое для
//                                                    данного варианта настройки. Образуется из URI
//                                                    пространства имен схемы расширения формата,
//                                                    без учета версии. Напр., для пространства
//                                                    имен "http://v8.1c.ru/edi/edi_stnd/_DemoEnterpriseDataExt/1.1" 
//                                                    имя расширение формата будет 
//                                                    "http://v8.1c.ru/edi/edi_stnd/_DemoEnterpriseDataExt";
//
Функция ОписаниеВариантаНастройкиОбменаПоУмолчанию(ИмяПланаОбмена) Экспорт
	
	МетаданныеПланаОбмена = Метаданные.ПланыОбмена[ИмяПланаОбмена];
	СинонимПланаОбмена    = МетаданныеПланаОбмена.Синоним;
	
	ЗаголовокФормыПомощника = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Синхронизация данных с %1 (настройка)'"),
		СинонимПланаОбмена);
		
	ОписаниеВарианта = Новый Структура;
	
	ОписаниеВарианта.Вставить("Отборы",                                                Новый Структура);
	ОписаниеВарианта.Вставить("ЗначенияПоУмолчанию",                                   Новый Структура);
	ОписаниеВарианта.Вставить("ОбщиеДанныеУзлов",                                      "");
	ОписаниеВарианта.Вставить("ИспользоватьПомощникСозданияОбменаДанными",             Истина);
	ОписаниеВарианта.Вставить("ИмяФормыСозданияНачальногоОбраза",                      "");
	ОписаниеВарианта.Вставить("ИмяФормыПомощникаНастройкиСинхронизацииДанных",         "");
	ОписаниеВарианта.Вставить("ПояснениеДляНастройкиПараметровУчета",                  "");
	ОписаниеВарианта.Вставить("ПутьКФайлуКомплектаПравилНаПользовательскомСайте",      "");
	ОписаниеВарианта.Вставить("ПутьКФайлуКомплектаПравилВКаталогеШаблонов",            "");
	ОписаниеВарианта.Вставить("ЗаголовокКомандыДляСозданияНовогоОбменаДанными",        СинонимПланаОбмена);
	ОписаниеВарианта.Вставить("ЗаголовокПомощникаСозданияОбмена",                      ЗаголовокФормыПомощника);
	ОписаниеВарианта.Вставить("ЗаголовокУзлаПланаОбмена",                              СинонимПланаОбмена);
	ОписаниеВарианта.Вставить("ИмяКонфигурацииКорреспондента",                         "");
	ОписаниеВарианта.Вставить("НаименованиеКонфигурацииКорреспондента",                "");
	ОписаниеВарианта.Вставить("ИспользуемыеТранспортыСообщенийОбмена",                 Новый Массив);
	ОписаниеВарианта.Вставить("КраткаяИнформацияПоОбмену",                             "");
	ОписаниеВарианта.Вставить("ПодробнаяИнформацияПоОбмену",                           "");
	ОписаниеВарианта.Вставить("ИмяФайлаНастроекДляПриемника",                          "");
	ОписаниеВарианта.Вставить("ПоддерживаетсяСопоставлениеДанных",                     Истина);
	ОписаниеВарианта.Вставить("РасширениеФормата",                                     "");

	Возврат ОписаниеВарианта;
	
КонецФункции

// Предназначена для подготовки структуры, для последующей передачи в обработчик получения описания варианта.
//
// Параметры:
//  ИмяКорреспондента - Строка - имя конфигурации-корреспондента.
//  ВерсияКорреспондента - Строка - версия конфигурации-корреспондента.
//
// Возвращаемое значение:
//   Структура:
//     * ИмяКорреспондента - Строка - имя конфигурации корреспондента.
//     * ВерсияКорреспондента - Строка - номер версии конфигурации корреспондента.
//
Функция ПараметрыКонтекстаПолученияОписанияВариантаНастройки(ИмяКорреспондента, ВерсияКорреспондента) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ИмяКорреспондента",    ИмяКорреспондента);
	Результат.Вставить("ВерсияКорреспондента", ВерсияКорреспондента);
	
	Возврат Результат;
	
КонецФункции

#Область НастройкиПодключенияКВнешнейСистеме

// Сохраняет настройки подключения для обмена с внешней системой через EnterpriseData. 
//
// Параметры:
//  Контекст - Структура - контекст выполнения операции:
//    * Режим - Строка - режим, в котором вызывается обработчик.
//                       Возможные значения: "НовоеПодключение" | "РедактированиеПараметровПодключения".
//    * Корреспондент - ПланОбменаСсылка
//                    - Неопределено - узел обмена, соответствующий корреспонденту.
//                                     Для режима "НовоеПодключение" равен Неопределено;
//    * ИмяПланаОбмена - Строка
//                     - Неопределено - имя плана обмена, на котором создается узел.
//    * ИдентификаторНастройки - Строка
//                             - Неопределено - идентификатор варианта настройки,
//                                              как он указан в модуле менеджера плана обмена.
//  ПараметрыПодключения - Структура - структура параметров подключения:
//    * ИдентификаторКорреспондента - Строка - строка длиной 36 символов
//                                  - Неопределено - уникальный идентификатор корреспондента.
//    * НаименованиеКорреспондента - Строка
//                                 - Неопределено - название корреспондента, как он будет отображаться
//                                                  в списке настроенных синхронизаций.
//    * НастройкиТранспорта - Произвольный
//                          - Неопределено - произвольное значение, описывающее параметры подключения.
//    * РасписаниеСинхронизации - РасписаниеРегламентногоЗадания
//                              - Неопределено - расписание запуска синхронизации.
//    * НастройкиXDTO - Структура
//                    - Неопределено - структура настроек XDTO корреспондента:
//      ** ПоддерживаемыеВерсии - Массив - перечень поддерживаемых корреспондентом версий формата.
//      ** ПоддерживаемыеОбъекты - см. ОбменДаннымиXDTOСервер.ПоддерживаемыеОбъектыФормата
//  Результат - Структура:
//    * УзелОбмена - ПланОбменаСсылка - узел плана обмена, соответствующий корреспонденту.
//    * ИдентификаторКорреспондента - Строка - уникальный идентификатор корреспондента.
//
Процедура ПриСохраненииНастроекПодключенияВнешнейСистемы(Контекст, ПараметрыПодключения, Результат) Экспорт
	
	Корреспондент = Неопределено;
	Контекст.Свойство("Корреспондент", Корреспондент);
	
	НастройкиXDTO = Неопределено;
	ПараметрыПодключения.Свойство("НастройкиXDTO", НастройкиXDTO);
	
	ВерсияФорматаОбмена = "";
	Если Не НастройкиXDTO = Неопределено Тогда
		Если НастройкиXDTO.ПоддерживаемыеВерсии <> Неопределено
			И НастройкиXDTO.ПоддерживаемыеВерсии.Количество() > 0 Тогда
			ВерсияФорматаОбмена = ОбменДаннымиXDTOСервер.МаксимальнаяОбщаяВерсияФормата(
				Контекст.ИмяПланаОбмена, НастройкиXDTO.ПоддерживаемыеВерсии);
		КонецЕсли;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	НачатьТранзакцию();
	Попытка
		Если Контекст.Режим = "НовоеПодключение" Тогда
			
			ИдентификаторКорреспондента = Неопределено;
			ПараметрыПодключения.Свойство("ИдентификаторКорреспондента", ИдентификаторКорреспондента);
			Если Не ЗначениеЗаполнено(ИдентификаторКорреспондента) Тогда
				ИдентификаторКорреспондента = XMLСтрока(Новый УникальныйИдентификатор);
			КонецЕсли;
			
			Корреспондент = НовыйУзелОбменаДаннымиXDTO(
				Контекст.ИмяПланаОбмена,
				Контекст.ИдентификаторНастройки,
				ИдентификаторКорреспондента,
				ПараметрыПодключения.НаименованиеКорреспондента,
				ВерсияФорматаОбмена);
			
			Если Не ОбщегоНазначения.РазделениеВключено() Тогда
				ВыполнитьОбновлениеПравилДляОбменаДанными();
			КонецЕсли;
			
			ТаблицаОбъектыБазы = ОбменДаннымиXDTOСервер.ПоддерживаемыеОбъектыФормата(
				Контекст.ИмяПланаОбмена, "ОтправкаПолучение", Корреспондент);
			
			МодульНастройкиОбменаДаннымиXDTO = ОбщегоНазначения.ОбщийМодуль("РегистрыСведений.НастройкиОбменаДаннымиXDTO");
			МодульНастройкиОбменаДаннымиXDTO.ОбновитьНастройки(
				Корреспондент, "ПоддерживаемыеОбъекты", ТаблицаОбъектыБазы);
				
			СтруктураЗаписи = Новый Структура;
			СтруктураЗаписи.Вставить("УзелИнформационнойБазы",       Корреспондент);
			СтруктураЗаписи.Вставить("ИмяПланаОбменаКорреспондента", Контекст.ИмяПланаОбмена);
			
			ОбменДаннымиСлужебный.ОбновитьЗаписьВРегистрСведений(СтруктураЗаписи, "НастройкиОбменаДаннымиXDTO");
		ИначеЕсли Контекст.Режим = "РедактированиеПараметровПодключения" Тогда
			ДанныеКорреспондента = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Корреспондент, "Код, Наименование, ВерсияФорматаОбмена");
			
			ЗначенияДляОбновления = Новый Структура;
			
			Если ПараметрыПодключения.Свойство("ИдентификаторКорреспондента")
				И ЗначениеЗаполнено(ПараметрыПодключения.ИдентификаторКорреспондента)
				И СокрЛП(ПараметрыПодключения.ИдентификаторКорреспондента) <> СокрЛП(ДанныеКорреспондента.Код) Тогда
				ЗначенияДляОбновления.Вставить("Код", СокрЛП(ПараметрыПодключения.ИдентификаторКорреспондента));
			КонецЕсли;
			
			Если ПараметрыПодключения.Свойство("НаименованиеКорреспондента")
				И ЗначениеЗаполнено(ПараметрыПодключения.НаименованиеКорреспондента)
				И СокрЛП(ПараметрыПодключения.НаименованиеКорреспондента) <> СокрЛП(ДанныеКорреспондента.Наименование) Тогда
				ЗначенияДляОбновления.Вставить("Наименование", СокрЛП(ПараметрыПодключения.НаименованиеКорреспондента));
			КонецЕсли;
			
			Если ЗначениеЗаполнено(ВерсияФорматаОбмена)
				И Не ВерсияФорматаОбмена = ДанныеКорреспондента.ВерсияФорматаОбмена Тогда
				ЗначенияДляОбновления.Вставить("ВерсияФорматаОбмена", ВерсияФорматаОбмена);
			КонецЕсли;
			
			Если ЗначенияДляОбновления.Количество() > 0 Тогда
				Блокировка = Новый БлокировкаДанных;
			    ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(Корреспондент));
			    ЭлементБлокировки.УстановитьЗначение("Ссылка", Корреспондент);
			    Блокировка.Заблокировать();
			    
				ЗаблокироватьДанныеДляРедактирования(Корреспондент);
				КорреспондентОбъект = Корреспондент.ПолучитьОбъект();
				
				Для Каждого ЗначениеДляОбновления Из ЗначенияДляОбновления Цикл
					КорреспондентОбъект[ЗначениеДляОбновления.Ключ] = ЗначениеДляОбновления.Значение;
				КонецЦикла;

			    КорреспондентОбъект.ОбменДанными.Загрузка = Истина;
				КорреспондентОбъект.Записать();
			КонецЕсли;
		Иначе
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не подходящий режим вызова функции: %1'"), Контекст.Режим);
		КонецЕсли;
		
		Если Не НастройкиXDTO = Неопределено Тогда
			Если Не НастройкиXDTO.ПоддерживаемыеОбъекты = Неопределено Тогда
				МодульНастройкиОбменаДаннымиXDTO = ОбщегоНазначения.ОбщийМодуль("РегистрыСведений.НастройкиОбменаДаннымиXDTO");
				МодульНастройкиОбменаДаннымиXDTO.ОбновитьНастройкиКорреспондента(
					Корреспондент, "ПоддерживаемыеОбъекты", НастройкиXDTO.ПоддерживаемыеОбъекты);
			КонецЕсли;
		КонецЕсли;
		
		МодульНастройкиТранспортаОбменаДанными = ОбщегоНазначения.ОбщийМодуль("РегистрыСведений.НастройкиТранспортаОбменаДанными");
		МодульНастройкиТранспортаОбменаДанными.СохранитьНастройкиТранспортаВнешнейСистемы(
			Корреспондент, ПараметрыПодключения.НастройкиТранспорта);
			
		Если ПараметрыПодключения.Свойство("РасписаниеСинхронизации")
			И ПараметрыПодключения.РасписаниеСинхронизации <> Неопределено Тогда
			
			ИспользоватьРегламентноеЗадание = ?(ПараметрыПодключения.Свойство("ИспользоватьРегламентноеЗадание"),
				ПараметрыПодключения.ИспользоватьРегламентноеЗадание, Истина);
				
			Если ОбщегоНазначения.РазделениеВключено() Тогда
				Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОчередьЗаданий") 
					И ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
					
					МодульОчередьЗаданий = ОбщегоНазначения.ОбщийМодуль("ОчередьЗаданий");
					МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
					
					КлючЗадания = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Обмен данными с внешней системой (%1)'"),
						ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Корреспондент, "Код"));
						
					ПараметрыЗадания = Новый Структура;
					ПараметрыЗадания.Вставить("ОбластьДанных", МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса());
					ПараметрыЗадания.Вставить("Использование", ИспользоватьРегламентноеЗадание);
					ПараметрыЗадания.Вставить("ИмяМетода",     "ОбменДаннымиСервер.ВыполнитьОбменДаннымиСВнешнейСистемой");
					
					ПараметрыЗадания.Вставить("Параметры", Новый Массив);
					ПараметрыЗадания.Параметры.Добавить(Корреспондент);
					ПараметрыЗадания.Параметры.Добавить(Новый Структура("ВыполнятьЗагрузку, ВыполнятьОтправкуНастроек", Истина, Истина));
					ПараметрыЗадания.Параметры.Добавить(Ложь);
					
					ПараметрыЗадания.Вставить("Ключ",       КлючЗадания);
					ПараметрыЗадания.Вставить("Расписание", ПараметрыПодключения.РасписаниеСинхронизации);
					
					Если Контекст.Режим = "НовоеПодключение" Тогда
						МодульОчередьЗаданий.ДобавитьЗадание(ПараметрыЗадания);
					ИначеЕсли Контекст.Режим = "РедактированиеПараметровПодключения" Тогда
						Отбор = Новый Структура("ОбластьДанных, ИмяМетода, Ключ");
						ЗаполнитьЗначенияСвойств(Отбор, ПараметрыЗадания);
						
						ТаблицаЗадания = МодульОчередьЗаданий.ПолучитьЗадания(Отбор);
						Если ТаблицаЗадания.Количество() > 0 Тогда
							МодульОчередьЗаданий.ИзменитьЗадание(ТаблицаЗадания[0].Идентификатор, ПараметрыЗадания);
						Иначе
							МодульОчередьЗаданий.ДобавитьЗадание(ПараметрыЗадания);
						КонецЕсли;
					КонецЕсли;
					
				КонецЕсли;
			Иначе
				Если Контекст.Режим = "НовоеПодключение" Тогда
					Справочники.СценарииОбменовДанными.СоздатьСценарий(
						Корреспондент, ПараметрыПодключения.РасписаниеСинхронизации, ИспользоватьРегламентноеЗадание);
				ИначеЕсли Контекст.Режим = "РедактированиеПараметровПодключения" Тогда
					Запрос = Новый Запрос(
					"ВЫБРАТЬ РАЗЛИЧНЫЕ
					|	СценарииОбменовДанными.Ссылка КАК Сценарий,
					|	СценарииОбменовДанными.Ссылка.ИспользоватьРегламентноеЗадание КАК ИспользоватьРегламентноеЗадание
					|ИЗ
					|	Справочник.СценарииОбменовДанными КАК СценарииОбменовДанными
					|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.СценарииОбменовДанными.НастройкиОбмена КАК СценарииОбменовДаннымиНастройкиОбмена
					|		ПО (СценарииОбменовДаннымиНастройкиОбмена.Ссылка = СценарииОбменовДанными.Ссылка)
					|ГДЕ
					|	СценарииОбменовДаннымиНастройкиОбмена.УзелИнформационнойБазы = &УзелИнформационнойБазы
					|	И НЕ СценарииОбменовДанными.ПометкаУдаления");
					Запрос.УстановитьПараметр("УзелИнформационнойБазы", Корреспондент);
					
					Выборка = Запрос.Выполнить().Выбрать();
					Если Выборка.Следующий() Тогда
						СценарийОбъект = Выборка.Сценарий.ПолучитьОбъект(); // СправочникОбъект.СценарииОбменовДанными
						
						Отказ = Ложь;
						Справочники.СценарииОбменовДанными.ОбновитьДанныеРегламентногоЗадания(
							Отказ, ПараметрыПодключения.РасписаниеСинхронизации, СценарийОбъект);
							
						Если Не Отказ Тогда
							СценарийОбъект.ИспользоватьРегламентноеЗадание = ИспользоватьРегламентноеЗадание;
							СценарийОбъект.Записать();
						КонецЕсли;
					КонецЕсли;
				КонецЕсли;
			КонецЕсли;
			
		КонецЕсли;
			
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	Если Контекст.Режим = "НовоеПодключение" Тогда
		// Отправка формализованных настроек XDTO.
		ПараметрыОбмена = Новый Структура;
		ПараметрыОбмена.Вставить("ВыполнятьЗагрузку",         Ложь);
		ПараметрыОбмена.Вставить("ВыполнятьОтправкуНастроек", Истина);
		
		Отказ             = Ложь;
		СообщениеОбОшибке = "";
		Попытка
			ВыполнитьОбменДаннымиСВнешнейСистемой(Корреспондент, ПараметрыОбмена, Отказ);
		Исключение
			Отказ = Истина;
			СообщениеОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСозданиеОбменаДанными(),
				УровеньЖурналаРегистрации.Ошибка, , , СообщениеОбОшибке);
		КонецПопытки;
		
		Если Отказ Тогда
			НастройкиУдаления = Новый Структура;
			НастройкиУдаления.Вставить("УзелОбмена", Корреспондент);
			НастройкиУдаления.Вставить("УдалитьНастройкуВКорреспонденте", Истина);
			
			ПараметрыПроцедуры = Новый Структура;
			ПараметрыПроцедуры.Вставить("НастройкиУдаления", НастройкиУдаления);
			
			АдресРезультата = "";
			Попытка
				МодульПомощникСозданияОбменаДанными().УдалитьНастройкуСинхронизации(ПараметрыПроцедуры, АдресРезультата);
			Исключение
				ВызватьИсключение;
			КонецПопытки;
			
			ВызватьИсключение СообщениеОбОшибке;
		КонецЕсли;
	КонецЕсли;
		
	Результат = Новый Структура;
	Результат.Вставить("УзелОбмена", Корреспондент);
	Результат.Вставить("ИдентификаторКорреспондента",
		ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Корреспондент, "Код"));
	
КонецПроцедуры

// Заполняет структуру сохраненных параметров подключения к внешней системе.
//
// Параметры:
//  Контекст - Структура - контекст выполнения операции:
//    * Корреспондент - ПланОбменаСсылка - узел обмена, соответствующий корреспонденту.
//  ПараметрыПодключения - Структура - структура параметров подключения:
//    * ИдентификаторКорреспондента - Строка - строка длиной 36 символов, уникальный идентификатор корреспондента.
//    * НаименованиеКорреспондента - Строка - название корреспондента, как он отображается
//                                            в списке настроенных синхронизаций.
//    * НастройкиТранспорта - Произвольный - сохраненные настройки транспорта сообщений обмена внешней системы.
//    * РасписаниеСинхронизации - РасписаниеРегламентногоЗадания - расписание автоматического запуска обмена.
//    * НастройкиXDTO - Структура
//                    - Неопределено - структура настроек XDTO корреспондента:
//      ** ПоддерживаемыеВерсии - Массив - перечень поддерживаемых корреспондентом версий формата.
//      ** ПоддерживаемыеОбъекты - см. ОбменДаннымиXDTOСервер.ПоддерживаемыеОбъектыФормата.
//
Процедура ПриПолученииНастроекПодключенияВнешнейСистемы(Контекст, ПараметрыПодключения) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ДанныеУзлаОбмена = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Контекст.Корреспондент, "Код, Наименование");
	
	ПараметрыПодключения = Новый Структура;
	ПараметрыПодключения.Вставить("ИдентификаторКорреспондента", ДанныеУзлаОбмена.Код);
	ПараметрыПодключения.Вставить("НаименованиеКорреспондента",  ДанныеУзлаОбмена.Наименование);
	ПараметрыПодключения.Вставить("НастройкиТранспорта",
		РегистрыСведений.НастройкиТранспортаОбменаДанными.НастройкиТранспортаВнешнейСистемы(Контекст.Корреспондент));
	ПараметрыПодключения.Вставить("РасписаниеСинхронизации");
	ПараметрыПодключения.Вставить("НастройкиXDTO", Новый Структура);
	
	ПараметрыПодключения.НастройкиXDTO.Вставить("ПоддерживаемыеВерсии",
		РегистрыСведений.НастройкиОбменаДаннымиXDTO.ЗначениеНастройкиКорреспондента(Контекст.Корреспондент, "ПоддерживаемыеВерсии"));
	ПараметрыПодключения.НастройкиXDTO.Вставить("ПоддерживаемыеОбъекты",
		РегистрыСведений.НастройкиОбменаДаннымиXDTO.ЗначениеНастройкиКорреспондента(Контекст.Корреспондент, "ПоддерживаемыеОбъекты"));
	
КонецПроцедуры
	
// Таблица настроек транспорта обмена для всех настроенных обменов данными с внешними системами.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//    * Корреспондент - ПланОбменаСсылка - узел обмена, соответствующий корреспонденту.
//    * НастройкиТранспорта - Произвольный - сохраненные настройки транспорта сообщений обмена внешней системы.
//
Функция ВсеНастройкиТранспортаОбменаСВнешнимиСистемами() Экспорт
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Корреспондент");
	Результат.Колонки.Добавить("НастройкиТранспорта");
	
	ОбщийТекстЗапроса = "";
	ПланыОбменаБСП = ОбменДаннымиПовтИсп.ПланыОбменаБСП();
	
	Для Каждого ПланОбмена Из ПланыОбменаБСП Цикл
		
		Если Не ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(ПланОбмена) Тогда
			Продолжить;
		КонецЕсли;
		
		ТекстЗапроса = 
		"ВЫБРАТЬ
		|	Т.Ссылка КАК Корреспондент,
		|	НастройкиТранспортаОбменаДанными.ПараметрыПодключенияВнешнейСистемы КАК ПараметрыПодключенияВнешнейСистемы
		|ИЗ
		|	#ТаблицаПланаОбмена КАК Т
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиТранспортаОбменаДанными КАК НастройкиТранспортаОбменаДанными
		|		ПО (НастройкиТранспортаОбменаДанными.Корреспондент = Т.Ссылка)
		|ГДЕ
		|	НЕ Т.ЭтотУзел
		|	И НастройкиТранспортаОбменаДанными.ВидТранспортаСообщенийОбменаПоУмолчанию = ЗНАЧЕНИЕ(Перечисление.ВидыТранспортаСообщенийОбмена.ВнешняяСистема)";
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТаблицаПланаОбмена", "ПланОбмена." + ПланОбмена);
		
		Если Не ПустаяСтрока(ОбщийТекстЗапроса) Тогда
			ОбщийТекстЗапроса = ОбщийТекстЗапроса + "
			|
			|ОБЪЕДИНИТЬ ВСЕ
			|
			|";
		КонецЕсли;
		
		ОбщийТекстЗапроса = ОбщийТекстЗапроса + ТекстЗапроса;
		
	КонецЦикла;
	
	Если ПустаяСтрока(ОбщийТекстЗапроса) Тогда
		Возврат Результат;
	КонецЕсли;
	
	Запрос = Новый Запрос(ОбщийТекстЗапроса);
	
	УстановитьПривилегированныйРежим(Истина);
	ТаблицаНастройки = Запрос.Выполнить().Выгрузить();
	
	Для Каждого СтрокаНастройки Из ТаблицаНастройки Цикл
		СтрокаРезультат = Результат.Добавить();
		СтрокаРезультат.Корреспондент = СтрокаНастройки.Корреспондент;
		СтрокаРезультат.НастройкиТранспорта = СтрокаНастройки.ПараметрыПодключенияВнешнейСистемы.Получить();
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область СохранениеНастроекСинхронизацииДанных

// Начинает сохранение настроек синхронизации данных в длительной операции.
// При сохранении настроек выполняется перенос на узел обмена переданных данных заполнения,
// и устанавливается признак, что настройка синхронизации завершена.
// Рекомендуется использовать в помощнике настройки синхронизации данных.
// 
// Параметры:
//  НастройкиСинхронизации - Структура - структура параметров для сохранения настроек:
//   * УзелОбмена - ПланОбменаСсылка - узел плана обмена, для которого выполняется сохранение настроек синхронизации.
//   * ДанныеЗаполнения - Структура - произвольная структура для заполнения настроек на узле.
//                                    Будет передана в алгоритм "ПриСохраненииНастроекСинхронизацииДанных" (при его наличии).
//  ПараметрыОбработчика   - Структура - исходящий служебный параметр. Зарезервирован для внутреннего использования.
//                                       Применяется для отслеживания состояния длительной операции.
//                                       На вход следует передавать реквизит формы типа "Произвольный",
//                                       не используемый ни в каких других операциях.
//  ПродолжитьОжидание     - Булево    - исходящий параметр. Истина, если сохранение настройки запущено в длительной операции.
//                                       Для отслеживания состояния в этом случае следует использовать процедуру 
//                                       ОбменДаннымиСервер.ПриОжиданииСохраненияНастроекСинхронизации.
//
Процедура ПриНачалеСохраненияНастроекСинхронизации(НастройкиСинхронизации, ПараметрыОбработчика, ПродолжитьОжидание = Истина) Экспорт
	
	МодульПомощникСозданияОбменаДанными().ПриНачалеСохраненияНастроекСинхронизации(НастройкиСинхронизации,
		ПараметрыОбработчика,
		ПродолжитьОжидание);
	
КонецПроцедуры

// Используется при ожидании завершения настройки синхронизации данных.
// Проверяет статус выполнения длительной операции по сохранению настройки, и возвращает признак
// необходимости продолжения ожидания, либо сообщает, что операция сохранения настройки завершена.
// 
// Параметры:
//  ПараметрыОбработчика   - Структура - входящий/исходящий служебный параметр. Зарезервирован для внутреннего использования.
//                                       Применяется для отслеживания состояния длительной операции.
//                                       На вход следует передавать реквизит формы типа "Произвольный",
//                                       который был использован при запуске настройки синхронизации
//                                       вызовом метода ОбменДаннымиСервер.ПриНачалеСохраненияНастроекСинхронизации.
//  ПродолжитьОжидание     - Булево    - исходящий параметр. Истина, если необходимо продолжить ожидание завершения
//                                       операции сохранения настройки синхронизации, Ложь - если настройка
//                                       синхронизации завершена.
//
Процедура ПриОжиданииСохраненияНастроекСинхронизации(ПараметрыОбработчика, ПродолжитьОжидание) Экспорт

	МодульПомощникСозданияОбменаДанными().ПриОжиданииСохраненияНастроекСинхронизации(ПараметрыОбработчика,
		ПродолжитьОжидание);
	
КонецПроцедуры

// Получает статус завершения операции настройки синхронизации. Вызывается, когда процедуры
// ОбменДаннымиСервер.ПриНачалеСохраненияНастроекСинхронизации или ОбменДаннымиСервер.ПриОжиданииСохраненияНастроекСинхронизации
// устанавливают флаг ПродолжитьОжидание в значение Ложь.
// 
// Параметры:
//  ПараметрыОбработчика   - Структура - входящий служебный параметр. Зарезервирован для внутреннего использования.
//                                       Применяется для получения состояния длительной операции.
//                                       На вход следует передавать реквизит формы типа "Произвольный",
//                                       который был использован при запуске настройки синхронизации
//                                       вызовом метода ОбменДаннымиСервер.ПриНачалеСохраненияНастроекСинхронизации.
//  СтатусЗавершения       - Структура - исходящий параметр, возвращает состояние завершения длительной операции:
//   * Отказ             - Булево - Истина, если при запуске, или в ходе выполнения длительной операции произошла ошибка.
//   * СообщениеОбОшибке - Строка - текст ошибки, произошедшей при выполнении длительной операции, если Отказ = Истина.
//   * Результат         - Структура - состояние сохранения настройки синхронизации:
//    ** НастройкиСохранены - Булево - Истина, если настройка синхронизации успешно завершена.
//    ** СообщениеОбОшибке  - Строка - текст ошибки, возникшей непосредственно в транзакции сохранения настройки синхронизации.
//
Процедура ПриЗавершенииСохраненияНастроекСинхронизации(ПараметрыОбработчика, СтатусЗавершения) Экспорт
	
	МодульПомощникСозданияОбменаДанными().ПриЗавершенииСохраненияНастроекСинхронизации(ПараметрыОбработчика,
		СтатусЗавершения);
	
КонецПроцедуры

#КонецОбласти

#Область ОбщиеНастройкиУзловИнформационныхБаз

// Устанавливает признак завершения настройки синхронизации данных.
//
// Параметры:
//   УзелОбмена - ПланОбменаСсылка - узел обмена, для которого необходимо установить признак.
//
Процедура ЗавершитьНастройкуСинхронизацииДанных(УзелОбмена) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если УзелОбмена = ПланыОбмена[ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелОбмена)].ЭтотУзел() Тогда
		Возврат;
	КонецЕсли;
	
	НачатьТранзакцию();
	Попытка
		
		Если Не НастройкаСинхронизацииЗавершена(УзелОбмена) Тогда
			// Изменения, зарегистрированные до момента завершения настройки синхронизации,
			// являются некорректными, т.к. еще не были установлены отборы.
			ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена);
			
			// Необходимо сбросить ранее установленный признак регистрации изменений для повторной отправки сообщения в МС.
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
				
				МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
				МодульОбменДаннымиВМоделиСервиса.ИзменитьПризнакНеобходимостиОбменаДаннымиВМоделиСервиса(Ложь);
				
			КонецЕсли;
			
		КонецЕсли;
		
		РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.УстановитьПризнакНастройкаЗавершена(УзелОбмена);
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Возвращает признак завершения настройки синхронизации для узла обмена.
//
// Параметры:
//   УзелОбмена - ПланОбменаСсылка - узел обмена, для которого необходимо получить признак.
//
// Возвращаемое значение:
//   Булево - Истина, если настройка синхронизации для переданного узла завершена.
//
Функция НастройкаСинхронизацииЗавершена(УзелОбмена) Экспорт
	
	Если ОбменДаннымиПовтИсп.ЭтоУзелОбменаСообщениями(УзелОбмена) Тогда
		Возврат Истина;
	Иначе
		УстановитьПривилегированныйРежим(Истина);
		
		Возврат РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.НастройкаЗавершена(УзелОбмена);
	КонецЕсли;
	
КонецФункции

// Устанавливает признак успешного создания начального образа узла РИБ.
//
// Параметры:
//   УзелОбмена - ПланОбменаСсылка - узел обмена, для которого необходимо установить признак.
//
Процедура ЗавершитьСозданиеНачальногоОбраза(УзелОбмена) Экспорт
	
	РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.УстановитьПризнакНачальныйОбразСоздан(УзелОбмена);
	
КонецПроцедуры

#КонецОбласти

#Область ДляВызоваИзДругихПодсистем

// СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса

// Возвращает ссылку на узел плана обмена, найденный по его коду.
// Если узел не найден, возвращается Неопределено.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, как оно задано в конфигураторе.
//  КодУзла - Строка - код узла плана обмена.
//
// Возвращаемое значение:
//  ПланОбменаСсылка - ссылка на найденный узел плана обмена.
//  Неопределено - в случае, если узел плана обмена не найден.
//
Функция УзелПланаОбменаПоКоду(ИмяПланаОбмена, КодУзла) Экспорт
	
	СсылкаУзел = ПланыОбмена[ИмяПланаОбмена].НайтиПоКоду(КодУзла);
	
	Если Не ЗначениеЗаполнено(СсылкаУзел) Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Возврат СсылкаУзел;
	
КонецФункции

// Возвращает Истина, если сеанс запущен в автономном рабочем месте.
// Возвращаемое значение:
//  Булево - признак запуска в автономном рабочем месте.
//
Функция ЭтоАвтономноеРабочееМесто() Экспорт
	
	Возврат ОбменДаннымиПовтИсп.РежимАвтономногоРабочегоМеста();
	
КонецФункции

// Определяет, является ли переданный узел плана обмена автономным рабочим местом.
//
// Параметры:
//  УзелИнформационнойБазы - ПланОбменаСсылка - проверяемый узел.
//
// Возвращаемое значение:
//  Булево - признак того что переданный узел является автономным рабочим местом.
//
Функция ЭтоУзелАвтономногоРабочегоМеста(Знач УзелИнформационнойБазы) Экспорт
	
	Возврат ОбменДаннымиПовтИсп.ЭтоУзелАвтономногоРабочегоМеста(УзелИнформационнойБазы);
	
КонецФункции

// Удаляет набор записей в регистре по переданным значениям структуры.
//
// Параметры:
//  СтруктураЗаписи - Структура - структура, по значениям которой необходимо удалить набор записей.
// 
Процедура УдалитьЗаписиСостоянияОбменовДанными(СтруктураЗаписи) Экспорт
	
	ОбменДаннымиСлужебный.УдалитьНаборЗаписейВРегистреСведений(СтруктураЗаписи, "СостоянияОбменовДанными");
	
КонецПроцедуры

// Удаляет набор записей в регистре по переданным значениям структуры.
//
// Параметры:
//  СтруктураЗаписи - Структура - структура, по значениям которой необходимо удалить набор записей.
// 
Процедура УдалитьЗаписиСостоянияУспешныхОбменовДанными(СтруктураЗаписи) Экспорт
	
	ОбменДаннымиСлужебный.УдалитьНаборЗаписейВРегистреСведений(СтруктураЗаписи, "СостоянияУспешныхОбменовДанными");
	
КонецПроцедуры

// Удаляет поставляемые правила для плана обмена (очищает данные в регистре).
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого удаляются правила.
//
Процедура УдалитьПоставляемыеПравила(ИмяПланаОбмена) Экспорт
	
	РегистрыСведений.ПравилаДляОбменаДанными.УдалитьПоставляемыеПравила(ИмяПланаОбмена);	
	
КонецПроцедуры

// Загружает поставляемые правила для плана обмена.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого загружаются правила.
//  ИмяФайлаПравил - Строка - полное имя файла правил обмена (*.zip).
//
Процедура ЗагрузитьПоставляемыеПравила(ИмяПланаОбмена, ИмяФайлаПравил) Экспорт
	
	РегистрыСведений.ПравилаДляОбменаДанными.ЗагрузитьПоставляемыеПравила(ИмяПланаОбмена, ИмяФайлаПравил);	
	
КонецПроцедуры

// Возвращает идентификатор настройки обмена, соответствующий конкретному корреспонденту.
// 
// Параметры:
//   ИмяПланаОбмена       - Строка - имя плана обмена, который используется для настройки обмена.
//   ВерсияКорреспондента - Строка - номер версии корреспондента, с которым настраивается обмен.
//   ИмяКорреспондента    - Строка - имя корреспондента (см. функцию ИмяКонфигурацииИсточника
//                          на стороне конфигурации-корреспондента).
//
// Возвращаемое значение:
//   Массив из Строка - массив строк с идентификаторами настройки для корреспондента.
// 
Функция ВариантыНастроекОбменаДляКорреспондента(ИмяПланаОбмена, ВерсияКорреспондента, ИмяКорреспондента) Экспорт
	
	НастройкиПланаОбмена = НастройкиПланаОбмена(ИмяПланаОбмена, ВерсияКорреспондента, ИмяКорреспондента, Истина);
	Если НастройкиПланаОбмена.ВариантыНастроекОбмена.Количество() = 0 Тогда
		Возврат Новый Массив;
	Иначе
		Возврат НастройкиПланаОбмена.ВариантыНастроекОбмена.ВыгрузитьКолонку("ИдентификаторНастройки");
	КонецЕсли;
	
КонецФункции

// Возвращает идентификатор настройки обмена, соответствующий конкретному корреспонденту.
// 
// Параметры:
//  ИмяПланаОбмена    - Строка - имя плана обмена, который используется для настройки обмена.
//  ИмяКорреспондента - Строка - имя корреспондента (см. функцию ИмяКонфигурацииИсточника
//                               на стороне конфигурации-корреспондента).
//
// Возвращаемое значение:
//  Строка - идентификатор настройки обмена.
// 
Функция ВариантНастройкиОбменаДляКорреспондента(ИмяПланаОбмена, ИмяКорреспондента) Экспорт
	
	НастройкиПланаОбмена = НастройкиПланаОбмена(ИмяПланаОбмена, "", ИмяКорреспондента, Истина);
	Если НастройкиПланаОбмена.ВариантыНастроекОбмена.Количество() = 0 Тогда
		Возврат "";
	Иначе
		Возврат НастройкиПланаОбмена.ВариантыНастроекОбмена[0].ИдентификаторНастройки;
	КонецЕсли;
	
КонецФункции

// Удаляет поставляемые правила регистрации объектов для плана обмена (очищает данные в регистре).
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого удаляются правила.
//
Процедура УдалитьПоставляемыеПравилаРегистрацииОбъектов(ИмяПланаОбмена) Экспорт
	
	РегистрыСведений.ПравилаДляОбменаДанными.УдалитьПоставляемыеПравилаРегистрацииОбъектов(ИмяПланаОбмена);	
	
КонецПроцедуры

// Загружает поставляемые правила регистрации объектов для плана обмена.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого загружаются правила.
//  ИмяФайлаПравил - Строка - полное имя файла правил регистрации объектов (*.xml).
//
Процедура ЗагрузитьПоставляемыеПравилаРегистрацииОбъектов(ИмяПланаОбмена, ИмяФайлаПравил) Экспорт
	
	РегистрыСведений.ПравилаДляОбменаДанными.ЗагрузитьПоставляемыеПравилаРегистрацииОбъектов(
		ИмяПланаОбмена,
		ИмяФайлаПравил);	
	
КонецПроцедуры

// Конец СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса

#КонецОбласти

#Область УстаревшиеПроцедурыИФункции

// Устарела. Выполняет добавление информации об установленном в константе количестве элементов в транзакции
// в структуру, содержащую параметры транспорта сообщений обмена.
//
// Параметры:
//  Результат - Структура - содержит параметры транспорта сообщений обмена.
// 
Процедура ДополнитьНастройкиТранспортаКоличествомЭлементовВТранзакции(Результат) Экспорт
	
	ОбменДаннымиСлужебный.ДополнитьНастройкиТранспортаКоличествомЭлементовВТранзакции(Результат);
	
КонецПроцедуры

// Устарела. Возвращает номер области по коду узла плана обмена (обмен сообщениями).
// 
// Параметры:
//  КодУзла - Строка - код узла плана обмена.
// 
// Возвращаемое значение:
//  Число - номер области.
//
Функция НомерОбластиИзКодаУзлаПланаОбмена(Знач КодУзла) Экспорт
	
	Возврат ОбменДаннымиСлужебный.НомерОбластиИзКодаУзлаПланаОбмена(КодУзла);
	
КонецФункции

// Устарела. Возвращает данные первой записи результата запроса в виде структуры.
// 
// Параметры:
//  РезультатЗапроса - РезультатЗапроса - результат запроса, содержащий данные для обработки.
// 
// Возвращаемое значение:
//  Структура - структура с результатом.
//
Функция РезультатЗапросаВСтруктуру(Знач РезультатЗапроса) Экспорт
	
	Возврат ОбменДаннымиСлужебный.РезультатЗапросаВСтруктуру(РезультатЗапроса);
	
КонецФункции

// Устарела. Следует использовать функцию ЗначениеНастройкиПланаОбмена,
// установив параметру ИмяПараметра одно из следующих значений:
//  - ЗаголовокКомандыДляСозданияНовогоОбменаДанными;
//  - ЗаголовокПомощникаСозданияОбмена;
//  - ЗаголовокУзлаПланаОбмена;
//  - НаименованиеКонфигурацииКорреспондента.
//
// Возвращает, если оно задано, переопределяемое имя плана обмена, 
// в зависимости от предопределенной настройки обмена.
// Параметры:
//   УзелПланаОбмена         - ПланОбменаСсылка - узел плана обмена, для которого необходимо получить переопределяемое
//                                                имя.
//   ИмяПараметраСИменемУзла - Строка - имя параметра, в настройках по умолчанию, из которого необходимо получить имя узла.
//   ВариантНастройки        - Строка - вариант настройки обмена.
//
// Возвращаемое значение:
//  Строка - переопределяемое имя плана обмена как оно заданно в конфигураторе.
//
Функция ПереопределяемоеИмяУзлаПланаОбмена(Знач УзелПланаОбмена, ИмяПараметраСИменемУзла, ВариантНастройки = "") Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ПредставлениеПланаОбмена = ЗначениеНастройкиПланаОбмена(
		УзелПланаОбмена.Метаданные().Имя,
		ИмяПараметраСИменемУзла,
		ВариантНастройки);
	
	УстановитьПривилегированныйРежим(Ложь);
	
	Возврат ПредставлениеПланаОбмена;
	
КонецФункции

// Устарела. Возвращает количество нерассмотренных проблем обмена данными. Используется для отображения
// количества проблем обмена в пользовательском интерфейсе. Например, для использования в заголовке
// гиперссылки для перехода к монитору проблем обмена.
//
// Параметры:
//   Узлы - Массив из ПланОбменаСсылка - узлы обмена.
//
// Возвращаемое значение:
//   Число - количество нерассмотренных проблем обмена данными.
// 
Функция КоличествоНерассмотренныхПроблем(Узлы = Неопределено) Экспорт
	
	Возврат КоличествоПроблемОбменаДанными(Узлы) + КоличествоПроблемВерсионирования(Узлы);
	
КонецФункции

// Устарела. Возвращает структуру заголовка гиперссылки для перехода к монитору проблем обмена данными.
// 
// Параметры:
//   Узлы - Массив из ПланОбменаСсылка - узлы обмена.
//
// Возвращаемое значение:
//   Структура:
//     * Заголовок - Строка   - заголовок гиперссылки.
//     * Картинка  - Картинка - картинка для гиперссылки.
//
Функция СтруктураЗаголовкаГиперссылкиМонитораПроблем(Узлы = Неопределено) Экспорт
	
	Количество = КоличествоНерассмотренныхПроблем(Узлы);
	
	Если Количество > 0 Тогда
		
		Заголовок = НСтр("ru = 'Предупреждения (%1)'");
		Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Заголовок, Количество);
		Картинка = БиблиотекаКартинок.Предупреждение;
		
	Иначе
		
		Заголовок = НСтр("ru = 'Предупреждений нет'");
		Картинка = Новый Картинка;
		
	КонецЕсли;
	
	СтруктураЗаголовка = Новый Структура;
	СтруктураЗаголовка.Вставить("Заголовок", Заголовок);
	СтруктураЗаголовка.Вставить("Картинка", Картинка);
	
	Возврат СтруктураЗаголовка;
	
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

#Область РазличногоНазначения

// Выполняет загрузку приоритетных данных, полученных из главного узла РИБ.
Процедура ЗагрузитьПриоритетныеДанныеВПодчиненныйУзелРИБ(Отказ = Ложь) Экспорт
	
	Если ОбменДаннымиСлужебный.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском(
			"ПропуститьЗагрузкуСообщенияОбменаДаннымиПередЗапуском") Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбменДаннымиСлужебный.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском(
			"ПропуститьЗагрузкуПриоритетныхДанныхПередЗапуском") Тогда
		Возврат;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРазрешена", Истина);
	УстановитьПривилегированныйРежим(Ложь);
	
	Попытка
		
		Если НЕ ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюДанных") Тогда
			
			Если ОбщегоНазначения.РазделениеВключено() Тогда
				
				ИспользоватьСинхронизациюДанных = Константы.ИспользоватьСинхронизациюДанных.СоздатьМенеджерЗначения();
				ИспользоватьСинхронизациюДанных.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов");
				ИспользоватьСинхронизациюДанных.ОбменДанными.Загрузка = Истина;
				ИспользоватьСинхронизациюДанных.Значение = Истина;
				ИспользоватьСинхронизациюДанных.Записать();
				
			Иначе
				
				Если ПолучитьИспользуемыеПланыОбмена().Количество() > 0 Тогда
					
					ИспользоватьСинхронизациюДанных = Константы.ИспользоватьСинхронизациюДанных.СоздатьМенеджерЗначения();
					ИспользоватьСинхронизациюДанных.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов");
					ИспользоватьСинхронизациюДанных.ОбменДанными.Загрузка = Истина;
					ИспользоватьСинхронизациюДанных.Значение = Истина;
					ИспользоватьСинхронизациюДанных.Записать();
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
		
		Если ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюДанных") Тогда
			
			УзелИнформационнойБазы = ГлавныйУзел();
			
			Если УзелИнформационнойБазы <> Неопределено Тогда
				
				РегистрыСведений.НастройкиТранспортаОбменаДанными.ПеренестиНастройкиТранспортаОбменаДаннымиКорреспондента(УзелИнформационнойБазы);
				ВидТранспорта = РегистрыСведений.НастройкиТранспортаОбменаДанными.ВидТранспортаСообщенийОбменаПоУмолчанию(УзелИнформационнойБазы);
				
				ИмяПараметра = "СтандартныеПодсистемы.ОбменДанными.ПравилаРегистрации."
					+ ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
				ПравилаРегистрацииОбновлены = СтандартныеПодсистемыСервер.ПараметрРаботыПрограммы(ИмяПараметра);
				Если ПравилаРегистрацииОбновлены = Неопределено Тогда
					ВыполнитьОбновлениеПравилДляОбменаДанными();
				КонецЕсли;
				ПравилаРегистрацииОбновлены = СтандартныеПодсистемыСервер.ПараметрРаботыПрограммы(ИмяПараметра);
				Если ПравилаРегистрацииОбновлены = Неопределено Тогда
					ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Не выполнено обновление кэша правил регистрации данных для плана обмена ""%1""'"),
						ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы));
				КонецЕсли;
				
				// Загрузка только параметров работы программы.
				ПараметрыОбмена = ПараметрыОбмена();
				ПараметрыОбмена.ВидТранспортаСообщенийОбмена = ВидТранспорта;
				ПараметрыОбмена.ВыполнятьЗагрузку = Истина;
				ПараметрыОбмена.ВыполнятьВыгрузку = Ложь;
				ПараметрыОбмена.ТолькоПараметры   = Истина;
				ВыполнитьОбменДаннымиДляУзлаИнформационнойБазы(УзелИнформационнойБазы, ПараметрыОбмена, Отказ);
				
			КонецЕсли;
			
		КонецЕсли;
		
	Исключение
		УстановитьПривилегированныйРежим(Истина);
		УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРазрешена", Ложь);
		УстановитьПривилегированныйРежим(Ложь);
		
		ВключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском();
		
		ЗаписьЖурналаРегистрации(
			НСтр("ru = 'Обмен данными.Загрузка приоритетных данных'", ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка,,,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		
		ВызватьИсключение
			НСтр("ru = 'Ошибка загрузки приоритетных данных из сообщения обмена.
			           |См. подробности в журнале регистрации.'");
	КонецПопытки;
	УстановитьПривилегированныйРежим(Истина);
	УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРазрешена", Ложь);
	УстановитьПривилегированныйРежим(Ложь);
	
	Если Отказ Тогда
		
		Если КонфигурацияИзменена() Тогда
			ВызватьИсключение
				НСтр("ru = 'Загружены изменения программы, полученные из главного узла.
				           |Завершите работу программы. Откройте программу в конфигураторе
				           |и выполните команду ""Обновить конфигурацию базы данных (F7)"".
				           |
				           |После этого запустите программу.'");
		КонецЕсли;
		
		ВключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском();
		
		ВызватьИсключение
			НСтр("ru = 'Ошибка загрузки приоритетных данных из сообщения обмена.
			           |См. подробности в журнале регистрации.'");
	КонецЕсли;
	
КонецПроцедуры

// Устанавливает признак повторения загрузки при ошибке загрузки или обновления.
// Очищает хранилище сообщения обмена, полученного из главного узла РИБ.
//
Процедура ВключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском() Экспорт
	
	ОчиститьСообщениеОбменаДаннымиИзГлавногоУзла();
	
	Константы.ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском.Установить(Истина);
	
КонецПроцедуры

// Выполняет инициализацию XML файла, для записи информации об объектах
// отмеченных к обработке обновления, для передачи их в подчиненный узел РИБ.
//
Процедура ИнициализироватьФайлСДаннымиОбновления(Параметры) Экспорт
	
	ФайлДляЗаписиXML = Неопределено;
	ИмяФайлаСИзменениями = Неопределено;
	
	Если СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ("СФильтром") Тогда
		
		ИмяФайлаСИзменениями = ПолноеИмяФайлаДанныхОтложенногоОбновления();
		
		ФайлДляЗаписиXML = Новый ЗаписьFastInfoset;
		ФайлДляЗаписиXML.ОткрытьФайл(ИмяФайлаСИзменениями);
		ФайлДляЗаписиXML.ЗаписатьОбъявлениеXML();
		ФайлДляЗаписиXML.ЗаписатьНачалоЭлемента("Objects");
		
	КонецЕсли;
	
	Параметры.ИмяФайлаСИзменениями = ИмяФайлаСИзменениями;
	Параметры.ЗаписьИзмененийДляПодчиненногоУзлаРИБСФильтрами = ФайлДляЗаписиXML;
	
КонецПроцедуры

// Выполняет инициализацию XML файла, для записи информации об объектах.
//
Процедура ЗаписатьДанныеДляОбновленияВФайл(Параметры, Данные, ВидДанных, ПолноеИмяОбъекта = "") Экспорт
	
	Если Не СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ("СФильтром") Тогда
		Возврат;
	КонецЕсли;
	
	Если Параметры.ЗаписьИзмененийДляПодчиненногоУзлаРИБСФильтрами = Неопределено Тогда
		ТекстИсключения = НСтр("ru = 'В обработчике неправильно организована работа с параметрами регистрации данных к обработке.'");
		ВызватьИсключение ТекстИсключения;
	КонецЕсли;
	
	ЗаписьXML = Параметры.ЗаписьИзмененийДляПодчиненногоУзлаРИБСФильтрами;
	ЗаписьXML.ЗаписатьНачалоЭлемента("Object");
	ЗаписьXML.ЗаписатьАтрибут("Queue", Строка(Параметры.Очередь));
	
	Если Не ЗначениеЗаполнено(ПолноеИмяОбъекта) Тогда
		ПолноеИмяОбъекта = Данные.Метаданные().ПолноеИмя();
	КонецЕсли;
	
	ЗаписьXML.ЗаписатьАтрибут("Type", ПолноеИмяОбъекта);
	
	Если ВРег(ВидДанных) = "ССЫЛКА" Тогда
		ЗаписьXML.ЗаписатьАтрибут("Ref", XMLСтрока(Данные.Ссылка));
	Иначе
		
		Если ВРег(ВидДанных) = "НЕЗАВИСИМЫЙРЕГИСТР" Тогда
			
			ЗаписьXML.ЗаписатьНачалоЭлемента("Filter");
			Для Каждого ЭлементОтбора Из Данные.Отбор Цикл
				
				Если ЗначениеЗаполнено(ЭлементОтбора.Значение) Тогда
					ЗаписьXML.ЗаписатьНачалоЭлемента(ЭлементОтбора.Имя);
					
					ТипДанных = ТипЗнч(ЭлементОтбора.Значение);
					ОбъектМетаданных =  Метаданные.НайтиПоТипу(ТипДанных);
					
					Если ОбъектМетаданных <> Неопределено Тогда
						ЗаписьXML.ЗаписатьАтрибут("Type", ОбъектМетаданных.ПолноеИмя());
					ИначеЕсли ТипДанных = Тип("УникальныйИдентификатор") Тогда
						ЗаписьXML.ЗаписатьАтрибут("Type", "УникальныйИдентификатор");
					Иначе
						ЗаписьXML.ЗаписатьАтрибут("Type", Строка(ТипДанных));
					КонецЕсли;
					
					ЗаписьXML.ЗаписатьАтрибут("Val", XMLСтрока(ЭлементОтбора.Значение));
					ЗаписьXML.ЗаписатьКонецЭлемента();
				КонецЕсли;
				
			КонецЦикла;
			ЗаписьXML.ЗаписатьКонецЭлемента();
			
		Иначе
			Регистратор = Данные.Отбор.Регистратор.Значение;
			ЗаписьXML.ЗаписатьАтрибут("FilterType", Строка(Регистратор.Метаданные().ПолноеИмя()));
			ЗаписьXML.ЗаписатьАтрибут("Ref",        XMLСтрока(Регистратор.Ссылка));
		КонецЕсли;
		
	КонецЕсли;
	
	ЗаписьXML.ЗаписатьКонецЭлемента();

КонецПроцедуры

// Выполняет регистрацию в подчиненном узле РИБ с фильтрами
// объектов зарегистрированных для отложенного обновления в главном узле РИБ.
//
Процедура ОбработатьДанныеДляОбновленияВПодчиненномУзле(Знач ЗначениеКонстанты) Экспорт
	
	Если Не СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ("СФильтром")
		Или Не ЭтоПодчиненныйУзелРИБ()
		Или НазначениеПланаОбмена(ГлавныйУзел().Метаданные().Имя) <> "РИБСФильтром" Тогда
		Возврат;
	КонецЕсли;
	
	МассивЗначений = ЗначениеКонстанты.Значение.Получить();
	Если ТипЗнч(МассивЗначений) <> Тип("Массив") Тогда
		Возврат;
	КонецЕсли;
	
	Для Каждого ХранилищеЗначений Из МассивЗначений Цикл
		ИмяФайла = ПолноеИмяФайлаДанныхОтложенногоОбновления();
		
		Если ХранилищеЗначений = Неопределено Тогда
			Возврат;
		КонецЕсли;
		
		ДвоичныеДанные = ХранилищеЗначений.Получить(); // ДвоичныеДанные
		Если ДвоичныеДанные = Неопределено Тогда
			Возврат;
		КонецЕсли;
		
		Если ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ() Тогда
			Запрос = Новый Запрос;
			Запрос.Текст = 
			"ВЫБРАТЬ
			|	ОбновлениеИнформационнойБазы.Ссылка КАК Узел
			|ИЗ
			|	ПланОбмена.ОбновлениеИнформационнойБазы КАК ОбновлениеИнформационнойБазы
			|ГДЕ
			|	НЕ ОбновлениеИнформационнойБазы.ЭтотУзел";
			
			Выборка = Запрос.Выполнить().Выбрать();
			Пока Выборка.Следующий() Цикл
				ПланыОбмена.УдалитьРегистрациюИзменений(Выборка.Узел);
			КонецЦикла;
		КонецЕсли;
		
		ДвоичныеДанные.Записать(ИмяФайла);
		
		ЧтениеXML = Новый ЧтениеFastInfoset;
		ЧтениеXML.ОткрытьФайл(ИмяФайла);
		
		ПараметрыОбработчикаСтруктура = ОбновлениеИнформационнойБазы.ОсновныеПараметрыОтметкиКОбработке();
		
		Пока ЧтениеXML.Прочитать() Цикл
			
			Если ЧтениеXML.Имя = "Object"
				И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
				
				ПараметрыОбработчикаСтруктура.Очередь = Число(ЧтениеXML.ЗначениеАтрибута("Queue"));
				ПолноеИмяОбъектаМетаданных            = СокрЛП(ЧтениеXML.ЗначениеАтрибута("Type"));
				ТипОбъектаМетаданных                  = Метаданные.НайтиПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
				МенеджерОбъекта                       = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
				ЭтоСсылочныйТипОбъекта                = ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ТипОбъектаМетаданных);
				
				Если ЭтоСсылочныйТипОбъекта Тогда
					ОбъектКОбработке = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(ЧтениеXML.ЗначениеАтрибута("Ref")));
				Иначе
					
					ОбъектКОбработке = МенеджерОбъекта.СоздатьНаборЗаписей();
					
					Если ОбщегоНазначения.ЭтоРегистрСведений(ТипОбъектаМетаданных)
						И ТипОбъектаМетаданных.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.Независимый Тогда
						
						ЧтениеXML.Прочитать();
						
						Если ЧтениеXML.Имя = "Filter"
							И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
							
							ЧтениеОтбора = Истина;
							
							Пока ЧтениеОтбора Цикл
								
								ЧтениеXML.Прочитать();
								
								Если ЧтениеXML.Имя = "Filter" И ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
									ЧтениеОтбора = Ложь;
									Продолжить;
								ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
									Продолжить;
								Иначе
									
									ЗначениеОтбора = ЧтениеXML.ЗначениеАтрибута("Val");
									Если ЗначениеЗаполнено(ЗначениеОтбора) Тогда
										
										ИмяОтбора         = ЧтениеXML.Имя;
										ТипЗначенияОтбора = ЧтениеXML.ЗначениеАтрибута("Type");
										МетаданныеЗначенияОтбора = Метаданные.НайтиПоПолномуИмени(ТипЗначенияОтбора);
										
										ЭлементОтбора = ОбъектКОбработке.Отбор.Найти(ИмяОтбора);
										
										Если ЭлементОтбора <> Неопределено Тогда
										
											Если МетаданныеЗначенияОтбора <> Неопределено Тогда
												
												МенеджерОбъектаОтбора = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ТипЗначенияОтбора);
												
												Если ОбщегоНазначения.ЭтоПеречисление(МетаданныеЗначенияОтбора) Тогда
													СсылкаНаЗначение = МенеджерОбъектаОтбора[ЗначениеОтбора];
												Иначе
													СсылкаНаЗначение = МенеджерОбъектаОтбора.ПолучитьСсылку(Новый УникальныйИдентификатор(ЗначениеОтбора));
												КонецЕсли;
												
												ЭлементОтбора.Установить(СсылкаНаЗначение);
												
											Иначе
												Если ВРег(СтрЗаменить(ТипЗначенияОтбора, " ", "")) = "УНИКАЛЬНЫЙИДЕНТИФИКАТОР" Тогда
													ЭлементОтбора.Установить(XMLЗначение(Тип("УникальныйИдентификатор"), ЗначениеОтбора));
												Иначе
													ЭлементОтбора.Установить(XMLЗначение(Тип(ТипЗначенияОтбора), ЗначениеОтбора));
												КонецЕсли;
											КонецЕсли;
											
										КонецЕсли;
										
									КонецЕсли;
									
								КонецЕсли;
								
							КонецЦикла;
							
						КонецЕсли;
						
					Иначе
						
						ЗначениеРегистратора  = Новый УникальныйИдентификатор(ЧтениеXML.ЗначениеАтрибута("Ref"));
						ПолноеИмяРегистратора = ЧтениеXML.ЗначениеАтрибута("FilterType");
						МенеджерРегистратора  = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяРегистратора);
						СсылкаНаРегистратор   = МенеджерРегистратора.ПолучитьСсылку(ЗначениеРегистратора);
						ОбменДаннымиСлужебный.УстановитьЗначениеЭлементаОтбора(ОбъектКОбработке.Отбор, "Регистратор", СсылкаНаРегистратор);
						
					КонецЕсли;
					
					ОбъектКОбработке.Прочитать();
					
				КонецЕсли;
				
				ОбновлениеИнформационнойБазы.ОтметитьКОбработке(ПараметрыОбработчикаСтруктура, ОбъектКОбработке);
				
			Иначе
				Продолжить;
			КонецЕсли;
			
		КонецЦикла;
		
		ЧтениеXML.Закрыть();
		
		Файл = Новый Файл(ИмяФайла);
		Если Файл.Существует() Тогда
			УдалитьФайлы(ИмяФайла);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Выполняет закрытие XML файла с записанной информацией об объектах
// зарегистрированных для отложенного обновления.
//
Процедура ЗавершитьЗаписьФайлаСДаннымиОбновления(Параметры) Экспорт
	
	ДанныеОбновления = ЗавершитьЗаписьФайлаИПолучитьДанныеОбновления(Параметры);
	
	Если ДанныеОбновления <> Неопределено Тогда
		СохранитьДанныеОбновления(ДанныеОбновления, Параметры.ИмяФайлаСИзменениями);
	КонецЕсли;
	
КонецПроцедуры

// Выполняет закрытие XML файла с записанной информацией об объектах
// зарегистрированных для отложенного обновления и возвращает содержимое файла.
//
// Параметры:
//  Параметры - см. ОбновлениеИнформационнойБазы.ОсновныеПараметрыОтметкиКОбработке
//
// Возвращаемое значение:
//  ХранилищеЗначения - содержимое файла.
//
Функция ЗавершитьЗаписьФайлаИПолучитьДанныеОбновления(Параметры) Экспорт
	
	Если Не СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ("СФильтром")
		Или ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ() Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Если Параметры.ЗаписьИзмененийДляПодчиненногоУзлаРИБСФильтрами = Неопределено Тогда
		ТекстИсключения = НСтр("ru = 'В обработчике неправильно организована работа с параметрами регистрации данных к обработке.'");
		ВызватьИсключение ТекстИсключения;
	КонецЕсли;
	
	ЗаписьXML = Параметры.ЗаписьИзмененийДляПодчиненногоУзлаРИБСФильтрами;
	ЗаписьXML.ЗаписатьКонецЭлемента();
	ЗаписьXML.Закрыть();
	
	ИмяФайлаСИзменениями = Параметры.ИмяФайлаСИзменениями;
	ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяФайлаСИзменениями);
	
	Возврат Новый ХранилищеЗначения(ДвоичныеДанныеФайла, Новый СжатиеДанных(9));
	
КонецФункции

// Сохраняет содержимое файла из ЗавершитьЗаписьФайлаИПолучитьДанныеОбновления()
// в константу ДанныеДляОтложенногоОбновления.
//
// Параметры:
//  ДанныеОбновления - ХранилищеЗначения - содержимое файла.
//  ИмяФайлаСИзменениями - Строка - имя файла, в котором находились данные.
//
Процедура СохранитьДанныеОбновления(ДанныеОбновления, ИмяФайлаСИзменениями) Экспорт
	
	Если ИмяФайлаСИзменениями = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных;
		Блокировка.Добавить("Константа.ДанныеДляОтложенногоОбновления");
		Блокировка.Заблокировать();
		
		ЗначениеКонстанты = Константы.ДанныеДляОтложенногоОбновления.Получить().Получить();
		Если ТипЗнч(ЗначениеКонстанты) <> Тип("Массив") Тогда
			ЗначениеКонстанты = Новый Массив;
		КонецЕсли;
		
		ЗначениеКонстанты.Добавить(ДанныеОбновления);

		Константы.ДанныеДляОтложенногоОбновления.Установить(Новый ХранилищеЗначения(ЗначениеКонстанты));
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	ФайлСДанными = Новый Файл(ИмяФайлаСИзменениями);
	Если ФайлСДанными.Существует() Тогда
		УдалитьФайлы(ИмяФайлаСИзменениями);
	КонецЕсли;
	
КонецПроцедуры

// Сбрасывает значение константы ЗаписьИзмененийДляПодчиненногоУзлаРИБСФильтрами при обновлении.
//
Процедура СброситьЗначениеКонстантыСИзменениямиДляПодчиненногоУзлаРИБСФильтрами() Экспорт
	
	Константы.ДанныеДляОтложенногоОбновления.Установить(Неопределено);
	
КонецПроцедуры

// Возвращает Истина, если настройка подчиненного узла РИБ не завершена и
// требуется обновления параметров работы программы, которые не участвуют в РИБ.
//
Функция НастройкаПодчиненногоУзлаРИБ() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат ЭтоПодчиненныйУзелРИБ()
	      И НЕ Константы.НастройкаПодчиненногоУзлаРИБЗавершена.Получить();
	
КонецФункции

// Выполняет обновление правил конвертации/регистрации объектов.
// Обновление выполняется для всех планов обмена, подключенных к подсистеме.
// Обновление правил выполняется только для типовых правил.
// Если для плана обмена правила были загружены из файла, то такие правила не обновляются.
//
Процедура ВыполнитьОбновлениеПравилДляОбменаДанными() Экспорт
	
	// Для сценария, когда в конфигурации был удален или переименован план обмена.
	УдалитьНеактуальныеЗаписиВРегистреПравилДляОбменаДанными();
	
	Если Не Константы.ИспользоватьСинхронизациюДанных.Получить()
		И Не ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	ПравилаОбменаЗагруженныеИзФайла = Новый Массив;
	ПравилаРегистрацииЗагруженныеИзФайла = Новый Массив;
	
	ВыполнитьПроверкуНаличияПравилОбменаЗагруженныхИзФайла(ПравилаОбменаЗагруженныеИзФайла, ПравилаРегистрацииЗагруженныеИзФайла);
	ВыполнитьОбновлениеВерсииТиповыхПравилДляОбменаДанными(ПравилаОбменаЗагруженныеИзФайла, ПравилаРегистрацииЗагруженныеИзФайла);
	
КонецПроцедуры

// См. ОбменДаннымиПовтИсп.КаталогВременногоХранилищаФайлов()
Функция КаталогВременногоХранилищаФайлов() Экспорт
	
	БезопасныйРежим = БезопасныйРежим();
	Возврат ОбменДаннымиПовтИсп.КаталогВременногоХранилищаФайлов(БезопасныйРежим);
	
КонецФункции

// Выполняет проверку подключения обработки транспорта по заданным настройкам.
//
Процедура ПроверитьПодключениеОбработкиТранспортаСообщенийОбмена(Отказ,
		СтруктураНастроек, ВидТранспорта, СообщениеОбОшибке = "", НовыеПароли = Неопределено) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	// Создаем экземпляр объекта обработки.
	ОбработкаОбъект = Обработки[ИмяОбработкиТранспортаСообщенийОбмена(ВидТранспорта)].Создать();
	
	// Инициализация свойств обработки переданными параметрами настроек.
	ЗаполнитьЗначенияСвойств(ОбработкаОбъект, СтруктураНастроек);
	
	Корреспондент = Неопределено;
	ЕстьКорреспондент = СтруктураНастроек.Свойство("Корреспондент", Корреспондент)
		Или СтруктураНастроек.Свойство("КонечнаяТочкаКорреспондента", Корреспондент);
		
	// Привилегированный режим установлен выше.
	Если ЕстьКорреспондент Тогда

		СтрокаПараметров = "COMПарольПользователя, FTPСоединениеПароль, WSПароль, ПарольАрхиваСообщенияОбмена,
			|FTPСоединениеПарольОбластейДанных, ПарольАрхиваСообщенияОбменаОбластейДанных";
		
		Если НовыеПароли = Неопределено Тогда
			Пароли = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(Корреспондент, СтрокаПараметров, Истина);
		Иначе
			Пароли = Новый Структура(СтрокаПараметров);
			ЗаполнитьЗначенияСвойств(Пароли, НовыеПароли);
		КонецЕсли;
		
		ЗаполнитьЗначенияСвойств(ОбработкаОбъект, Пароли);
		
		Если ОбщегоНазначения.РазделениеВключено()
			И ТипЗнч(ОбработкаОбъект) = Тип("ОбработкаОбъект.ТранспортСообщенийОбменаFTP") Тогда
			ОбработкаОбъект.FTPСоединениеПароль = Пароли.FTPСоединениеПарольОбластейДанных;
			ОбработкаОбъект.ПарольАрхиваСообщенияОбмена = Пароли.ПарольАрхиваСообщенияОбменаОбластейДанных;
		КонецЕсли;
		
	КонецЕсли;
	
	// Инициализация транспорта обмена.
	ОбработкаОбъект.Инициализация();
	
	// Выполняем проверку подключения.
	Если Не ОбработкаОбъект.ПодключениеУстановлено() Тогда
		
		Отказ = Истина;
		
		СообщениеОбОшибке = ОбработкаОбъект.СтрокаСообщенияОбОшибке
			+ Символы.ПС + НСтр("ru = 'Техническую информацию об ошибке см. в журнале регистрации.'");
		
		ЗаписьЖурналаРегистрации(НСтр("ru = 'Транспорт сообщений обмена'", ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОбъект.СтрокаСообщенияОбОшибкеЖР);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ПроверитьВозможностьАдминистрированияОбменов() Экспорт
	
	Если Не ЕстьПраваНаАдминистрированиеОбменов() Тогда
		
		ВызватьИсключение НСтр("ru = 'Недостаточно прав для администрирования синхронизации данных.'");
		
	КонецЕсли;
	
КонецПроцедуры

// Получает узел распределенной информационной базы, являющийся главным для текущей информационной базы при условии,
// что распределенная информационная база создана на базе плана обмена, обслуживаемым подсистемой обмена данными БСП.
//
// Возвращаемое значение:
//  ПланОбменаСсылка.<ИмяПланаОбмена>, Неопределено - если текущая информационная база не является
//   узлом распределенной информационной базы
//   или главный узел для нее не определен (она сама является корневым узлом)
//   или распределенная информационная база создана на базе плана обмена, который не обслуживается подсистемой обмена
//   данными БСП, то метод возвращает Неопределено.
//
Функция ГлавныйУзел() Экспорт
	
	Результат = ПланыОбмена.ГлавныйУзел();
	
	Если Результат <> Неопределено Тогда
		
		Если Не ОбменДаннымиПовтИсп.ЭтоУзелОбменаДаннымиБСП(Результат) Тогда
			
			Результат = Неопределено;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Процедура ПриПродолженииНастройкиПодчиненногоУзлаРИБ() Экспорт
	
	ИнтеграцияПодсистемБСП.ПриНастройкеПодчиненногоУзлаРИБ();
	ОбменДаннымиПереопределяемый.ПриНастройкеПодчиненногоУзлаРИБ();
	
КонецПроцедуры

// Возвращает признак наличия у пользователя прав на выполнение синхронизации данных.
// Выполнять синхронизацию данных может, либо полноправный пользователь,
// либо пользователь с правами поставляемого профиля "Синхронизация данных с другими программами".
//
//  Параметры:
// Пользователь - ПользовательИнформационнойБазы
//              - Неопределено.
// Пользователь, для которого необходимо вычислить признак разрешения использования синхронизации данных.
// Если параметр не задан, то функция вычисляется для текущего пользователя информационной базы.
//
Функция СинхронизацияДанныхРазрешена(Знач Пользователь = Неопределено) Экспорт
	
	Если Пользователь = Неопределено Тогда
		Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
	КонецЕсли;
	
	Если Пользователь.Роли.Содержит(Метаданные.Роли.ПолныеПрава) Тогда
		Возврат Истина;
	КонецЕсли;
	
	РолиПрофиля = СтрРазделить(РолиПрофиляДоступаСинхронизацияДанныхСДругимиПрограммами(), ",");
	Для Каждого Роль Из РолиПрофиля Цикл
		
		Если Не Пользователь.Роли.Содержит(Метаданные.Роли.Найти(СокрЛП(Роль))) Тогда
			Возврат Ложь;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Истина;
КонецФункции

// Параметры:
//   Приемник - ТаблицаЗначений
//            - ТабличнаяЧасть - приемник данных.
//   Источник - ТаблицаЗначений
//            - ТабличнаяЧасть - источник данных.
//
Процедура ЗаполнитьТаблицуЗначений(Приемник, Знач Источник) Экспорт
	Приемник.Очистить();
	
	Если ТипЗнч(Источник)=Тип("ТаблицаЗначений") Тогда
		КолонкиИсточника = Источник.Колонки;
	Иначе
		Времянка = Источник.Выгрузить(Новый Массив);
		КолонкиИсточника = Времянка.Колонки;
	КонецЕсли;
	
	Если ТипЗнч(Приемник)=Тип("ТаблицаЗначений") Тогда
		КолонкиПриемника = Приемник.Колонки;
		КолонкиПриемника.Очистить();
		Для Каждого Колонка Из КолонкиИсточника Цикл
			ЗаполнитьЗначенияСвойств(КолонкиПриемника.Добавить(), Колонка);
		КонецЦикла;
	КонецЕсли;
	
	Для Каждого Строка Из Источник Цикл
		ЗаполнитьЗначенияСвойств(Приемник.Добавить(), Строка);
	КонецЦикла;
КонецПроцедуры

Функция ПолученоСообщениеСДаннымиДляСопоставления(УзелОбмена) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	СообщенияДляСопоставленияДанных.ПолученоСообщениеДляСопоставленияДанных КАК ПолученоСообщениеДляСопоставленияДанных
	|ИЗ
	|	#ТаблицаПланаОбмена КАК ТаблицаПланаОбмена
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ СообщенияДляСопоставленияДанных КАК СообщенияДляСопоставленияДанных
	|		ПО (СообщенияДляСопоставленияДанных.УзелИнформационнойБазы = ТаблицаПланаОбмена.Ссылка)
	|ГДЕ
	|	ТаблицаПланаОбмена.Ссылка = &УзелОбмена");
	Запрос.УстановитьПараметр("УзелОбмена", УзелОбмена);
	Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ТаблицаПланаОбмена", "ПланОбмена." + ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелОбмена));
	
	ПолучитьСообщенияДляСопоставленияДанных(Запрос.МенеджерВременныхТаблиц);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Если Выборка.Следующий() Тогда
		Возврат Выборка.ПолученоСообщениеДляСопоставленияДанных;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция КодУзлаПланаОбменаСтрокой(Значение) Экспорт
	
	Если ТипЗнч(Значение) = Тип("Строка") Тогда
		
		Возврат СокрЛП(Значение);
		
	ИначеЕсли ТипЗнч(Значение) = Тип("Число") Тогда
		
		Возврат Формат(Значение, "ЧЦ=7; ЧВН=; ЧГ=0");
		
	КонецЕсли;
	
	Возврат Значение;
КонецФункции

// Получает параметр защищенного соединения.
//
Функция ЗащищенноеСоединение(Путь) Экспорт
	
	Возврат ?(НРег(Лев(Путь, 4)) = "ftps", ОбщегоНазначенияКлиентСервер.НовоеЗащищенноеСоединение(), Неопределено);
	
КонецФункции

Процедура ЗарегистрироватьДанныеДляНачальнойВыгрузки(УзелИнформационнойБазы, Данные = Неопределено, УдалитьРегистрациюСоответствий = Истина) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	// Обновляем повторно используемые значения Механизма регистрации объектов.
	ОбменДаннымиСлужебный.ПроверитьКэшМеханизмаРегистрацииОбъектов();
	
	СтандартнаяОбработка = Истина;
	
	ОбменДаннымиПереопределяемый.РегистрацияИзмененийНачальнойВыгрузкиДанных(УзелИнформационнойБазы, СтандартнаяОбработка, Данные);
	
	Если СтандартнаяОбработка Тогда
		
		Если ТипЗнч(Данные) = Тип("Массив") Тогда
			
			Для Каждого ОбъектМетаданных Из Данные Цикл
				
				ПланыОбмена.ЗарегистрироватьИзменения(УзелИнформационнойБазы, ОбъектМетаданных);
				
			КонецЦикла;
			
		Иначе
			
			ПланыОбмена.ЗарегистрироватьИзменения(УзелИнформационнойБазы, Данные);
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если ОбменДаннымиПовтИсп.ПланОбменаСодержитОбъект(ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы),
		Метаданные.РегистрыСведений.СоответствияОбъектовИнформационныхБаз.ПолноеИмя())
		И УдалитьРегистрациюСоответствий Тогда
		
		ПланыОбмена.УдалитьРегистрациюИзменений(УзелИнформационнойБазы, Метаданные.РегистрыСведений.СоответствияОбъектовИнформационныхБаз);
		
	КонецЕсли;
	
	// Устанавливаем признак начальной выгрузки данных для узла.
	РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.УстановитьПризнакНачальнойВыгрузкиДанных(УзелИнформационнойБазы);
	
КонецПроцедуры

Процедура ЗарегистрироватьТолькоСправочникиДляНачальнойВыгрузки(Знач УзелИнформационнойБазы) Экспорт
	
	ЗарегистрироватьДанныеДляНачальнойВыгрузки(УзелИнформационнойБазы, СправочникиПланаОбмена(УзелИнформационнойБазы));
	
КонецПроцедуры

Процедура ЗарегистрироватьТолькоСправочникиДляНачальнойВыгрузкиВФоне(ПараметрыПроцедуры, АдресХранилища) Экспорт
	
	ЗарегистрироватьТолькоСправочникиДляНачальнойВыгрузки(ПараметрыПроцедуры["УзелИнформационнойБазы"]);
	
КонецПроцедуры

Процедура ЗарегистрироватьВсеДанныеКромеСправочниковДляНачальнойВыгрузки(Знач УзелИнформационнойБазы) Экспорт
	
	ЗарегистрироватьДанныеДляНачальнойВыгрузки(УзелИнформационнойБазы, ВсеДанныеПланаОбменаКромеСправочников(УзелИнформационнойБазы));
	
КонецПроцедуры

Процедура ЗарегистрироватьВсеДанныеКромеСправочниковДляНачальнойВыгрузкиВФоне(ПараметрыПроцедуры, АдресХранилища) Экспорт
	
	ЗарегистрироватьВсеДанныеКромеСправочниковДляНачальнойВыгрузки(ПараметрыПроцедуры["УзелИнформационнойБазы"]);
	
КонецПроцедуры

Функция ДанныеДляТабличныхЧастейУзловЭтойИнформационнойБазы(Знач ИмяПланаОбмена, ВерсияКорреспондента = "", ИдентификаторНастройки = "") Экспорт
	
	Результат = Новый Структура;
	
	ОбщиеТаблицыУзлов = ОбменДаннымиПовтИсп.ТабличныеЧастиПланаОбмена(ИмяПланаОбмена, ВерсияКорреспондента, ИдентификаторНастройки)["ВсеТаблицыЭтойБазы"];
	
	Для Каждого ИмяТабличнойЧасти Из ОбщиеТаблицыУзлов Цикл
		
		ИмяТаблицы = ИмяТаблицыИзПервогоРеквизитаТабличнойЧастиПланаОбмена(ИмяПланаОбмена, ИмяТабличнойЧасти);
		
		Если Не ЗначениеЗаполнено(ИмяТаблицы) Тогда
			Продолжить;
		КонецЕсли;
		
		ДанныеТабличнойЧасти = Новый ТаблицаЗначений;
		ДанныеТабличнойЧасти.Колонки.Добавить("Представление",                 Новый ОписаниеТипов("Строка"));
		ДанныеТабличнойЧасти.Колонки.Добавить("УникальныйИдентификаторСсылки", Новый ОписаниеТипов("Строка"));
		
		ТекстЗапроса =
		"ВЫБРАТЬ ПЕРВЫЕ 1000
		|	ИмяТаблицыПланаОбмена.Ссылка КАК Ссылка,
		|	ИмяТаблицыПланаОбмена.Представление КАК Представление
		|ИЗ
		|	&ИмяТаблицыПланаОбмена КАК ИмяТаблицыПланаОбмена
		|
		|ГДЕ
		|	НЕ ИмяТаблицыПланаОбмена.ПометкаУдаления
		|
		|УПОРЯДОЧИТЬ ПО
		|	ИмяТаблицыПланаОбмена.Представление";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицыПланаОбмена", ИмяТаблицы);
		
		Запрос = Новый Запрос;
		Запрос.Текст = ТекстЗапроса;
		
		Выборка = Запрос.Выполнить().Выбрать();
		
		Пока Выборка.Следующий() Цикл
			
			СтрокаТаблицы = ДанныеТабличнойЧасти.Добавить();
			СтрокаТаблицы.Представление = Выборка.Представление;
			СтрокаТаблицы.УникальныйИдентификаторСсылки = Строка(Выборка.Ссылка.УникальныйИдентификатор());
			
		КонецЦикла;
		
		Результат.Вставить(ИмяТабличнойЧасти, ДанныеТабличнойЧасти);
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПолучитьЗначенияНастройкиОтборов(СтруктураНастроекВнешнегоСоединения) Экспорт
	
	Результат = Новый Структура;
	
	// объектные типы
	Для Каждого НастройкаОтбора Из СтруктураНастроекВнешнегоСоединения Цикл
		
		Если ТипЗнч(НастройкаОтбора.Значение) = Тип("Структура") Тогда
			
			РезультатВложенный = Новый Структура;
			
			Для Каждого Элемент Из НастройкаОтбора.Значение Цикл
				
				Если СтрНайти(Элемент.Ключ, "_Ключ") > 0 Тогда
					
					Ключ = СтрЗаменить(Элемент.Ключ, "_Ключ", "");
					
					Массив = Новый Массив;
					
					Для Каждого ЭлементМассива Из Элемент.Значение Цикл
						
						Если Не ПустаяСтрока(ЭлементМассива) Тогда
							
							Значение = ЗначениеИзСтрокиВнутр(ЭлементМассива);
							
							Массив.Добавить(Значение);
							
						КонецЕсли;
						
					КонецЦикла;
					
					РезультатВложенный.Вставить(Ключ, Массив);
					
				КонецЕсли;
				
			КонецЦикла;
			
			Результат.Вставить(НастройкаОтбора.Ключ, РезультатВложенный);
			
		Иначе
			
			Если СтрНайти(НастройкаОтбора.Ключ, "_Ключ") > 0 Тогда
				
				Ключ = СтрЗаменить(НастройкаОтбора.Ключ, "_Ключ", "");
				
				Попытка
					Если ПустаяСтрока(НастройкаОтбора.Значение) Тогда
						Значение = Неопределено;
					Иначе
						Значение = ЗначениеИзСтрокиВнутр(НастройкаОтбора.Значение);
					КонецЕсли;
				Исключение
					Значение = Неопределено;
				КонецПопытки;
				
				Результат.Вставить(Ключ, Значение);
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	// примитивные типы
	Для Каждого НастройкаОтбора Из СтруктураНастроекВнешнегоСоединения Цикл
		
		Если ТипЗнч(НастройкаОтбора.Значение) = Тип("Структура") Тогда
			
			РезультатВложенный = Результат[НастройкаОтбора.Ключ];
			
			Если РезультатВложенный = Неопределено Тогда
				
				РезультатВложенный = Новый Структура;
				
			КонецЕсли;
			
			Для Каждого Элемент Из НастройкаОтбора.Значение Цикл
				
				Если СтрНайти(Элемент.Ключ, "_Ключ") <> 0 Тогда
					
					Продолжить;
					
				ИначеЕсли НастройкаОтбора.Значение.Свойство(Элемент.Ключ + "_Ключ") Тогда
					
					Продолжить;
					
				КонецЕсли;
				
				Массив = Новый Массив;
				
				Для Каждого ЭлементМассива Из Элемент.Значение Цикл
					
					Массив.Добавить(ЭлементМассива);
					
				КонецЦикла;
				
				РезультатВложенный.Вставить(Элемент.Ключ, Массив);
				
			КонецЦикла;
			
		Иначе
			
			Если СтрНайти(НастройкаОтбора.Ключ, "_Ключ") <> 0 Тогда
				
				Продолжить;
				
			ИначеЕсли СтруктураНастроекВнешнегоСоединения.Свойство(НастройкаОтбора.Ключ + "_Ключ") Тогда
				
				Продолжить;
				
			КонецЕсли;
			
			// Экранирование перечисления
			Если ТипЗнч(НастройкаОтбора.Значение) = Тип("Строка")
				И (     СтрНайти(НастройкаОтбора.Значение, "Перечисление.") <> 0
					ИЛИ СтрНайти(НастройкаОтбора.Значение, "Enumeration.") <> 0) Тогда
				
				Результат.Вставить(НастройкаОтбора.Ключ, ПредопределенноеЗначение(НастройкаОтбора.Значение));
				
			Иначе
				
				Результат.Вставить(НастройкаОтбора.Ключ, НастройкаОтбора.Значение);
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция ПараметрыИнформационнойБазы(Знач ИмяПланаОбмена, 
									Знач КодУзла, 
									СообщениеОбОшибке, 
									ДополнительныеПараметры = Неопределено) Экспорт 
	
	Результат = Новый Структура;
	
	Результат.Вставить("ПланОбменаСуществует",                      Ложь);
	Результат.Вставить("ПрефиксИнформационнойБазы",                 "");
	Результат.Вставить("ПрефиксИнформационнойБазыПоУмолчанию",      "");
	Результат.Вставить("НаименованиеИнформационнойБазы",            "");
	Результат.Вставить("НаименованиеИнформационнойБазыПоУмолчанию", "");
	Результат.Вставить("НастройкиПараметровУчетаЗаданы",            Ложь);
	Результат.Вставить("КодЭтогоУзла",                              "");
	// Начиная с версии БСП 2.1.5.1.
	Результат.Вставить("ВерсияКонфигурации",                        Метаданные.Версия);
	// Начиная с версии БСП 2.4.2(?).
	Результат.Вставить("УзелСуществует",                            Ложь);
	// Начиная с версии БСП 3.0.1.1.
	Результат.Вставить("ВерсияФорматаНастроекОбменаДанными",        МодульПомощникСозданияОбменаДанными().ВерсияФорматаНастроекОбменаДанными());
	Результат.Вставить("ИспользоватьПрефиксыДляНастройкиОбмена",    Истина);
	Результат.Вставить("ФорматОбмена",                              "");
	Результат.Вставить("ИмяПланаОбмена",                            ИмяПланаОбмена);
	Результат.Вставить("ВерсииФорматаОбмена",                       Новый Массив);
	Результат.Вставить("ПоддерживаемыеОбъектыФормата",              Неопределено);
	
	Результат.Вставить("НастройкаСинхронизацииДанныхЗавершена",     Ложь);
	Результат.Вставить("ПолученоСообщениеДляСопоставленияДанных",   Ложь);
	Результат.Вставить("ПоддерживаетсяСопоставлениеДанных",         Истина);
	
	УстановитьПривилегированныйРежим(Истина);
	
	Результат.ПланОбменаСуществует = (Метаданные.ПланыОбмена.Найти(ИмяПланаОбмена) <> Неопределено);

	Если Не Результат.ПланОбменаСуществует 
		И ДополнительныеПараметры <> Неопределено
		И ДополнительныеПараметры.Свойство("ЭтоПланОбменаXDTO") Тогда
		
		ПланОбмена = НайтиИмяПланаОбменаЧерезУниверсальныйФормат(ИмяПланаОбмена);
			
		Результат.ПланОбменаСуществует = ЗначениеЗаполнено(ПланОбмена);
		Результат.ИмяПланаОбмена = ПланОбмена;
	
	КонецЕсли;
	
	Если Не Результат.ПланОбменаСуществует Тогда
		Возврат Результат;
	КонецЕсли;
	
	ЭтотУзел = ПланыОбмена[Результат.ИмяПланаОбмена].ЭтотУзел();
	
	СвойстваЭтогоУзла = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ЭтотУзел, "Код, Наименование");
	
	ПрефиксИнформационнойБазы = Неопределено;
	ОбменДаннымиПереопределяемый.ПриОпределенииПрефиксаИнформационнойБазыПоУмолчанию(ПрефиксИнформационнойБазы);
	
	УзелКорреспондента = Неопределено;
	Если ЗначениеЗаполнено(КодУзла) Тогда
		УзелКорреспондента = УзелПланаОбменаПоКоду(Результат.ИмяПланаОбмена, КодУзла);
	КонецЕсли;
	
	Результат.ПрефиксИнформационнойБазы            = ПолучитьФункциональнуюОпцию("ПрефиксИнформационнойБазы");
	Результат.ПрефиксИнформационнойБазыПоУмолчанию = ПрефиксИнформационнойБазы;
	
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Результат.НаименованиеИнформационнойБазы = Константы.ЗаголовокСистемы.Получить();
	КонецЕсли;
	Если ПустаяСтрока(Результат.НаименованиеИнформационнойБазы) Тогда
		Результат.НаименованиеИнформационнойБазы = СвойстваЭтогоУзла.Наименование;
	КонецЕсли;
	
	Результат.УзелСуществует                       = ЗначениеЗаполнено(УзелКорреспондента);
	Результат.НастройкиПараметровУчетаЗаданы       = Результат.УзелСуществует
		И НастройкиПараметровУчетаВСистемеУстановлены(Результат.ИмяПланаОбмена, КодУзла, СообщениеОбОшибке);
	Результат.КодЭтогоУзла                         = СвойстваЭтогоУзла.Код;
	Результат.ВерсияКонфигурации                   = Метаданные.Версия;
	
	Результат.НаименованиеИнформационнойБазыПоУмолчанию = ?(ОбщегоНазначения.РазделениеВключено(),
		Метаданные.Синоним, ОбменДаннымиПовтИсп.ИмяЭтойИнформационнойБазы());
		
	Если ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(Результат.ИмяПланаОбмена) Тогда
		Результат.ИспользоватьПрефиксыДляНастройкиОбмена = 
			Не ОбменДаннымиXDTOСервер.ПоддерживаетсяВерсияСИдентификаторомОбменаДанными(ЭтотУзел);
			
		СвойстваПланаОбмена = ЗначениеНастройкиПланаОбмена(Результат.ИмяПланаОбмена, "ВерсииФорматаОбмена, ФорматОбмена");
		
		Результат.ФорматОбмена        = СвойстваПланаОбмена.ФорматОбмена;
		Результат.ВерсииФорматаОбмена = ОбщегоНазначения.ВыгрузитьКолонку(СвойстваПланаОбмена.ВерсииФорматаОбмена, "Ключ", Истина);
		
		Результат.Вставить("ПоддерживаемыеОбъектыФормата",
			ОбменДаннымиXDTOСервер.ПоддерживаемыеОбъектыФормата(Результат.ИмяПланаОбмена, "ОтправкаПолучение", УзелКорреспондента));
	КонецЕсли;
		
	Если Результат.УзелСуществует Тогда
		Результат.НастройкаСинхронизацииДанныхЗавершена   = НастройкаСинхронизацииЗавершена(УзелКорреспондента);
		Результат.ПолученоСообщениеДляСопоставленияДанных = ПолученоСообщениеСДаннымиДляСопоставления(УзелКорреспондента);
		Результат.ПоддерживаетсяСопоставлениеДанных = ЗначениеНастройкиПланаОбмена(Результат.ИмяПланаОбмена,
			"ПоддерживаетсяСопоставлениеДанных", СохраненныйВариантНастройкиУзлаПланаОбмена(УзелКорреспондента));
	КонецЕсли;
			
	Возврат Результат;
	
КонецФункции

// Возвращает Истина при необходимости обновления конфигурации информационной базы подчиненного узла РИБ.
// В главном узле всегда - Ложь.
// 
// Копия функции ОбщегоНазначения.ТребуетсяОбновлениеКонфигурацииПодчиненногоУзлаРИБ.
// 
Функция ТребуетсяУстановкаОбновления() Экспорт
	
	Возврат ЭтоПодчиненныйУзелРИБ() 
		И (КонфигурацияИзменена() ИЛИ ОбменДаннымиСлужебный.ЗагрузитьРасширенияИзменяющиеСтруктуруДанных());
	
КонецФункции

// Предназначена для подготовки структуры, для последующей передачи в обработчик получения вариантов настроек.
//
// Параметры:
//  ИмяКорреспондента - Строка - имя конфигурации-корреспондента.
//  ВерсияКорреспондента - Строка - версия конфигурации-корреспондента.
//  КорреспондентВМоделиСервиса - Булево
//                              - Неопределено - признак того, что корреспондент находится в модели сервиса.
//
// Возвращаемое значение:
//   Структура:
//     * ВерсияКорреспондента - Строка - номер версии конфигурации корреспондента.
//     * ИмяКорреспондента - Строка - имя конфигурации корреспондента.
//     * КорреспондентВМоделиСервиса - Булево - Истина, если корреспондент работает в модели сервиса.
//
Функция ПараметрыКонтекстаПолученияВариантовНастроек(ИмяКорреспондента, ВерсияКорреспондента, КорреспондентВМоделиСервиса) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ИмяКорреспондента",           ИмяКорреспондента);
	Результат.Вставить("ВерсияКорреспондента",        ВерсияКорреспондента);
	Результат.Вставить("КорреспондентВМоделиСервиса", КорреспондентВМоделиСервиса);
	
	Возврат Результат;
	
КонецФункции

// Возвращает пустую таблицу вариантов настройки обмена.
//
// Возвращаемое значение:
//   ТаблицаЗначений:
//     * ИдентификаторНастройки        - Строка - идентификатор настройки.
//     * КорреспондентВМоделиСервиса   - Булево - Истина, если поддерживается настройка обмена
//                                                с корреспондентом, работающим в модели сервиса.
//     * КорреспондентВЛокальномРежиме - Булево - Истина, если поддерживается настройка обмена
//                                                с корреспондентом, работающим в локальном режиме.
//
Функция КоллекцияВариантовНастроекОбмена() Экспорт
	
	ВариантыНастроекОбмена = Новый ТаблицаЗначений;
	ВариантыНастроекОбмена.Колонки.Добавить("ИдентификаторНастройки",        Новый ОписаниеТипов("Строка"));
	ВариантыНастроекОбмена.Колонки.Добавить("КорреспондентВМоделиСервиса",   Новый ОписаниеТипов("Булево"));
	ВариантыНастроекОбмена.Колонки.Добавить("КорреспондентВЛокальномРежиме", Новый ОписаниеТипов("Булево"));
	
	Возврат ВариантыНастроекОбмена;
	
КонецФункции

// Получение файла по его идентификатору.
//
// Параметры:
//  ИдентификаторФайла - УникальныйИдентификатор - идентификатор получаемого файла.
//  WSПассивныйРежимФайловаяИБ - Булево - признак того, что получение файла происходит в файловой ИБ при настройке WS
//                                        соединения в пассивном режиме
//
// Возвращаемое значение:
//  ИмяФайла - Строка - имя файла.
//
Функция ПолучитьФайлИзХранилища(Знач ИдентификаторФайла, WSПассивныйРежимФайловаяИБ = Ложь) Экспорт
	
	ИмяФайла = "";
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
		МодульОбменДаннымиВМоделиСервиса.ПриПолученииФайлаИзХранилища(ИдентификаторФайла, ИмяФайла);
		
	Иначе
		
		ПриПолученииФайлаИзХранилища(ИдентификаторФайла, ИмяФайла);
		
	КонецЕсли;
	
	Если WSПассивныйРежимФайловаяИБ Тогда
		ПолноеИмяФайла = ПолноеИмяФайлаДляСопоставленияФайловаяИБ(ИмяФайла);	
	Иначе
		ПолноеИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременногоХранилищаФайлов(), ИмяФайла);	
	КонецЕсли;
	
	Возврат ПолноеИмяФайла;
	
КонецФункции

// Сохранение файла.
//
// Параметры:
//  ИмяФайла               - Строка - наименование файла.
//  ИдентификаторФайла     - УникальныйИдентификатор - идентификатор файла. Если задан, то при сохранении файла
//                           будет использоваться это значение, иначе - сгенерируется новое.
//
// Возвращаемое значение:
//  УникальныйИдентификатор - идентификатор файла.
//
Функция ПоместитьФайлВХранилище(Знач ИмяФайла, Знач ИдентификаторФайла = Неопределено) Экспорт
	
	ИдентификаторФайла = ?(ИдентификаторФайла = Неопределено, Новый УникальныйИдентификатор, ИдентификаторФайла);
	
	Файл = Новый Файл(ИмяФайла);
	
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("ИдентификаторСообщения", Строка(ИдентификаторФайла));
	СтруктураЗаписи.Вставить("ИмяФайлаСообщения", Файл.Имя);
	СтруктураЗаписи.Вставить("ДатаЗакладкиСообщения", ТекущаяУниверсальнаяДата());
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
		МодульОбменДаннымиВМоделиСервиса.ПриПомещенииФайлаВХранилище(СтруктураЗаписи);
	Иначе
		
		ПриПомещенииФайлаВХранилище(СтруктураЗаписи);
		
	КонецЕсли;
	
	Возврат ИдентификаторФайла;
	
КонецФункции

// Структура описания стандартных вариантов дополнения выгрузки.
//
// Возвращаемое значение:
//   Структура - набор вариантов дополнения выгрузки:
//     * ВариантБезДополнения - см. ОписаниеСтандартногоВариантаБезДополнения
//     * ВариантВсеДокументы - см. ОписаниеСтандартногоВариантаВсеДокументы
//     * ВариантПроизвольныйОтбор - см. ОписаниеСтандартногоВариантаПроизвольныйОтбор
//     * ВариантДополнительно - см. ОписаниеСтандартногоВариантаДополнительно
//
Функция ОписаниеСтандартныхВариантовДополненияВыгрузки() Экспорт
	
	Результат = Новый Структура;
	
	Результат.Вставить("ВариантБезДополнения",     ОписаниеСтандартногоВариантаБезДополнения());
	Результат.Вставить("ВариантВсеДокументы",      ОписаниеСтандартногоВариантаВсеДокументы());
	Результат.Вставить("ВариантПроизвольныйОтбор", ОписаниеСтандартногоВариантаПроизвольныйОтбор());
	Результат.Вставить("ВариантДополнительно",     ОписаниеСтандартногоВариантаДополнительно());
	
	Возврат Результат;
	
КонецФункции

Процедура ПроверитьВозможностьЗапускаОбмена(УзелОбмена, Отказ) Экспорт
	
	Попытка
		
		// Проверка не должна устанавливать/снимать блокировок
		ЗаблокироватьДанныеДляРедактирования(УзелОбмена);
		РазблокироватьДанныеДляРедактирования(УзелОбмена);
		
	Исключение
		
		Отказ = Истина;
		
		СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось выполнить обмен данными с %1.
			|Обмен данными уже выполняется. Повторите попытку позже.'"),
			УзелОбмена);
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Предупреждение,
			УзелОбмена.Метаданные(), УзелОбмена, СообщениеОбОшибке);
			
	КонецПопытки;
	
КонецПроцедуры

Функция ЭтоТехническийОбъект(Знач ПолноеИмяОбъекта) Экспорт
	
	Если СтрНайти(ПолноеИмяОбъекта, ВРег("ПланОбмена")) > 0 Тогда
		
		Для Каждого ИмяПланаОбмена Из ОбменДаннымиПовтИсп.ПланыОбменаБСП() Цикл
			
			Если СтрНайти(ПолноеИмяОбъекта, ВРег(ИмяПланаОбмена)) Тогда
				Возврат Истина;
			КонецЕсли;
			
		КонецЦикла;	
						
	КонецЕсли;
		
	Возврат Ложь;
	
КонецФункции

#КонецОбласти

#Область ОберткиДляРаботыСПрограммнымИнтерфейсомМенеджераПланаОбмена

Функция НастройкаОтборовНаУзле(Знач ИмяПланаОбмена, Знач ВерсияКорреспондента, ИдентификаторНастройки = "") Экспорт
	Если ПустаяСтрока(ВерсияКорреспондента) Тогда
		ВерсияКорреспондента = "0.0.0.0";
	КонецЕсли;
	ОписаниеВариантаНастройки = ОбменДаннымиПовтИсп.ОписаниеВариантаНастройки(ИмяПланаОбмена, 
								ИдентификаторНастройки, ВерсияКорреспондента);
	
	Результат = Неопределено;
	Если ЗначениеЗаполнено(ОписаниеВариантаНастройки.Отборы) Тогда
		Результат = ОписаниеВариантаНастройки.Отборы;
	КонецЕсли;
	
	Если Результат = Неопределено Тогда
		Результат = Новый Структура;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция ОписаниеОграниченийПередачиДанных(Знач ИмяПланаОбмена, Знач Настройка, Знач ВерсияКорреспондента, 
										ИдентификаторНастройки = "") Экспорт
	Если НЕ ЕстьАлгоритмМенеджераПланаОбмена("ОписаниеОграниченийПередачиДанных", ИмяПланаОбмена) Тогда
		Возврат "";
	ИначеЕсли ПустаяСтрока(ВерсияКорреспондента) Тогда
		ВерсияКорреспондента = "0.0.0.0";
	КонецЕсли;
	
	Возврат ПланыОбмена[ИмяПланаОбмена].ОписаниеОграниченийПередачиДанных(Настройка, ВерсияКорреспондента, ИдентификаторНастройки);
	
КонецФункции

// Возвращает признак, предусмотрен ли указанная процедура / функция в модуле менеджера плана обмена.
// Вычисляется по настройкам плана обмена, свойство Алгоритмы (см. комментарий  НастройкиПланаОбменаПоУмолчанию).
// Параметры:
//  ИмяАлгоритма - Строка - имя процедуры / функции.
//  ИмяПланаОбмена - Строка - имя плана обмена.
// Возвращаемое значение:
//   Булево.
//
Функция ЕстьАлгоритмМенеджераПланаОбмена(ИмяАлгоритма, ИмяПланаОбмена) Экспорт
	
	НастройкиПланаОбмена = ОбменДаннымиПовтИсп.НастройкиПланаОбмена(ИмяПланаОбмена);
	
	АлгоритмНайден = Неопределено;
	НастройкиПланаОбмена.Алгоритмы.Свойство(ИмяАлгоритма, АлгоритмНайден);
	
	Возврат (АлгоритмНайден = Истина);
	
КонецФункции

#КонецОбласти

#Область ПрогрессБар

// Рассчитывает процент выгрузки и записывает в виде сообщения пользователю.
//
// Параметры:
//  КоличествоВыгруженных       - Число - количество выгруженных на данный момент объектов.
//  КоличествоОбъектовКВыгрузке - Число - количество объектов к выгрузке.
//
Процедура РассчитатьПроцентВыгрузки(КоличествоВыгруженных, КоличествоОбъектовКВыгрузке) Экспорт
	
	// Сообщение о проценте выгрузки выдаем через каждые 100 объектов.
	Если КоличествоВыгруженных = 0 ИЛИ КоличествоВыгруженных / 100 <> Цел(КоличествоВыгруженных / 100) Тогда
		Возврат;
	КонецЕсли;
	
	Если КоличествоОбъектовКВыгрузке = 0 Или КоличествоВыгруженных > КоличествоОбъектовКВыгрузке Тогда
		ПроцентВыполнения = 95;
		Шаблон = НСтр("ru = 'Обработано: %1 объектов.'");
		Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, Формат(КоличествоВыгруженных, "ЧН=0; ЧГ="));
	Иначе
		// 5% полосы резервируем под выгрузку по ссылкам, проценты по количеству считаем от 95.
		ПроцентВыполнения = Окр(Мин(КоличествоВыгруженных * 95 / КоличествоОбъектовКВыгрузке, 95));
		Шаблон = НСтр("ru = 'Обработано: %1 из %2 объектов.'");
		Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			Шаблон,
			Формат(КоличествоВыгруженных, "ЧН=0; ЧГ="),
			Формат(КоличествоОбъектовКВыгрузке, "ЧН=0; ЧГ="));
	КонецЕсли;
	
	// Регистрация сообщения для чтения из клиентского сеанса.
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ОбменДанными", Истина);
	
	ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, Текст, ДополнительныеПараметры);
КонецПроцедуры

// Рассчитывает процент загрузки и записывает в виде сообщения пользователю.
//
// Параметры:
//  КоличествоЗагруженных       - Число - количество загруженных на данный момент объектов.
//  КоличествоОбъектовКЗагрузке - Число - количество объектов к загрузке.
//  РазмерФайлаСообщенияОбмена  - Число - размер файла сообщения обмена в мегабайтах.
//
Процедура РассчитатьПроцентЗагрузки(КоличествоЗагруженных, КоличествоОбъектовКЗагрузке, РазмерФайлаСообщенияОбмена) Экспорт
	// Сообщение о проценте загрузки выдаем через каждые 10 объектов.
	Если КоличествоЗагруженных = 0 ИЛИ КоличествоЗагруженных / 10 <> Цел(КоличествоЗагруженных / 10) Тогда
		Возврат;
	КонецЕсли;

	Если КоличествоОбъектовКЗагрузке = 0 Тогда
		// Возможно при загрузке через com соединение если на другой стороне не встроен прогресс-бар.
		ПроцентВыполнения = 95;
		Шаблон = НСтр("ru = 'Обработано %1 объектов.'");
		Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, Формат(КоличествоЗагруженных, "ЧН=0; ЧГ="));
	Иначе
		// 5% полосы резервируем под отложенное заполнение, проценты по количеству считаем от 95.
		ПроцентВыполнения = Окр(Мин(КоличествоЗагруженных * 95 / КоличествоОбъектовКЗагрузке, 95));
		
		Шаблон = НСтр("ru = 'Обработано: %1 из %2 объектов.'");
		Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			Шаблон,
			Формат(КоличествоЗагруженных, "ЧН=0; ЧГ="),
			Формат(КоличествоОбъектовКЗагрузке, "ЧН=0; ЧГ="));
	КонецЕсли;
	
	// Дополняем размером файла.
	Если РазмерФайлаСообщенияОбмена <> 0 Тогда
		Шаблон = НСтр("ru = 'Размер сообщения %1 МБ'");
		ТекстДополнение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, РазмерФайлаСообщенияОбмена);
		Текст = Текст + " " + ТекстДополнение;
	КонецЕсли;
	
	// Регистрация сообщения для чтения из клиентского сеанса.
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ОбменДанными", Истина);
	
	ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, Текст, ДополнительныеПараметры);

КонецПроцедуры

// Увеличение счетчика выгруженных объектов и расчет процента выгрузки. Только для РИБ.
//
// Параметры:
//   Получатель - ПланОбменаОбъект
//   СозданиеНачальногоОбраза - Булево
//
Процедура РассчитатьПроцентВыгрузкиРИБ(Получатель, СозданиеНачальногоОбраза) Экспорт
	
	Если Получатель = Неопределено
		Или Не ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(Получатель.Ссылка) Тогда
		Возврат;
	КонецЕсли;
	
	// Подсчет количества объектов к выгрузке.
	Если НЕ Получатель.ДополнительныеСвойства.Свойство("КоличествоОбъектовКВыгрузке") Тогда
		КоличествоОбъектовКВыгрузке = 0;
		Если СозданиеНачальногоОбраза Тогда
			КоличествоОбъектовКВыгрузке = РассчитатьКоличествоОбъектовВБазе(Получатель);
		Иначе
			// Извлечение общего количества объектов к выгрузке.
			ТекущийПараметрСеанса = Неопределено;
			УстановитьПривилегированныйРежим(Истина);
			Попытка
				ТекущийПараметрСеанса = ПараметрыСеанса.ПараметрыСеансаСинхронизацииДанных.Получить();
			Исключение
				Возврат;
			КонецПопытки;
			УстановитьПривилегированныйРежим(Ложь);
			Если ТипЗнч(ТекущийПараметрСеанса) = Тип("Соответствие") Тогда
				ДанныеСинхронизации = ТекущийПараметрСеанса.Получить(Получатель.Ссылка);
				Если НЕ (ДанныеСинхронизации = Неопределено 
					ИЛИ ТипЗнч(ДанныеСинхронизации) <> Тип("Структура")) Тогда
					КоличествоОбъектовКВыгрузке = ДанныеСинхронизации.КоличествоОбъектовКВыгрузке;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		Получатель.ДополнительныеСвойства.Вставить("КоличествоОбъектовКВыгрузке", КоличествоОбъектовКВыгрузке);
		Получатель.ДополнительныеСвойства.Вставить("СчетчикВыгруженныхОбъектов", 1);
		Возврат; // % выгрузки в этом случае можно не считать - это самое начало выгрузки.
	Иначе
		Если Получатель.ДополнительныеСвойства.Свойство("СчетчикВыгруженныхОбъектов") Тогда
			Получатель.ДополнительныеСвойства.СчетчикВыгруженныхОбъектов = Получатель.ДополнительныеСвойства.СчетчикВыгруженныхОбъектов + 1;
		Иначе
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	РассчитатьПроцентВыгрузки(Получатель.ДополнительныеСвойства.СчетчикВыгруженныхОбъектов,
		Получатель.ДополнительныеСвойства.КоличествоОбъектовКВыгрузке);
КонецПроцедуры

// Увеличение счетчика загруженных объектов и расчет процента загрузки. Только для РИБ.
//
// Параметры:
//   Отправитель - ПланОбменаОбъект
//
Процедура РассчитатьПроцентЗагрузкиРИБ(Отправитель) Экспорт
	
	Если Отправитель = Неопределено
		Или Не ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(Отправитель.Ссылка) Тогда
		Возврат;
	КонецЕсли;
	Если НЕ Отправитель.ДополнительныеСвойства.Свойство("КоличествоОбъектовКЗагрузке")
		ИЛИ НЕ Отправитель.ДополнительныеСвойства.Свойство("РазмерФайлаСообщенияОбмена") Тогда
		// Извлечение общего количества объектов к загрузке и размера файла сообщения обмена.
		ТекущийПараметрСеанса = Неопределено;
		УстановитьПривилегированныйРежим(Истина);
		Попытка
			ТекущийПараметрСеанса = ПараметрыСеанса.ПараметрыСеансаСинхронизацииДанных.Получить();
		Исключение
			Возврат;
		КонецПопытки;
		УстановитьПривилегированныйРежим(Ложь);
		Если ТипЗнч(ТекущийПараметрСеанса) = Тип("Соответствие") Тогда
			ДанныеСинхронизации = ТекущийПараметрСеанса.Получить(Отправитель.Ссылка);
			Если ДанныеСинхронизации = Неопределено 
				ИЛИ ТипЗнч(ДанныеСинхронизации) <> Тип("Структура") Тогда
				Возврат;
			КонецЕсли;
			Отправитель.ДополнительныеСвойства.Вставить("КоличествоОбъектовКЗагрузке", 
														ДанныеСинхронизации.КоличествоОбъектовКЗагрузке);
			Отправитель.ДополнительныеСвойства.Вставить("РазмерФайлаСообщенияОбмена", 
														ДанныеСинхронизации.РазмерФайлаСообщенияОбмена);
		КонецЕсли;
	КонецЕсли;
	Если Не Отправитель.ДополнительныеСвойства.Свойство("СчетчикЗагруженныхОбъектов") Тогда
		Отправитель.ДополнительныеСвойства.Вставить("СчетчикЗагруженныхОбъектов", 1);
	Иначе
		Отправитель.ДополнительныеСвойства.СчетчикЗагруженныхОбъектов = Отправитель.ДополнительныеСвойства.СчетчикЗагруженныхОбъектов + 1;
	КонецЕсли;
	
	РассчитатьПроцентЗагрузки(Отправитель.ДополнительныеСвойства.СчетчикЗагруженныхОбъектов,
		Отправитель.ДополнительныеСвойства.КоличествоОбъектовКЗагрузке,
		Отправитель.ДополнительныеСвойства.РазмерФайлаСообщенияОбмена);
	
КонецПроцедуры

// Анализирует данные к загрузке:
// Вычисляет количество объектов к загрузке, размер файла сообщения обмена, другие служебные данные.
// Параметры:
//  ИмяФайлаОбмена - Строка - имя файла сообщения обмена.
//  ЭтоОбменXDTO - Булево - признак того, что выполняется обмен через универсальный формат.
// 
// Возвращаемое значение:
//  Структура:
//    * РазмерФайлаСообщенияОбмена  - Число - размер файла в мегабайтах, по умолчанию 0.
//    * КоличествоОбъектовКЗагрузке - Число - количество объектов к загрузке, по умолчанию 0.
//    * From - Строка - код узла-отправителя сообщения.
//    * To - Строка - код узла-получателя сообщения.
//    * NewFrom - Строка - код узла-отправителя в новом формате (для перевода существующих обменов на новую кодировку).
//
Функция РезультатАнализаДанныхКЗагрузке(Знач ИмяФайлаОбмена, ЭтоОбменXDTO, ЭтоОбменРИБ = Ложь) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("РазмерФайлаСообщенияОбмена", 0);
	Результат.Вставить("КоличествоОбъектовКЗагрузке", 0);
	Результат.Вставить("From", "");
	Результат.Вставить("NewFrom", "");
	Результат.Вставить("To", "");
	
	Если НЕ ЗначениеЗаполнено(ИмяФайлаОбмена) Тогда
		Возврат Результат;
	КонецЕсли;
	
	ФайлСДанными = Новый Файл(ИмяФайлаОбмена);
	Если Не ФайлСДанными.Существует() Тогда
		Возврат Результат;
	КонецЕсли;
	
	ФайлОбмена = Новый ЧтениеXML;
	Попытка
		// Размер сразу переводим в мегабайты.
		Результат.РазмерФайлаСообщенияОбмена = Окр(ФайлСДанными.Размер() / 1048576, 1);
		ФайлОбмена.ОткрытьФайл(ИмяФайлаОбмена);
	Исключение
		Возврат Результат;
	КонецПопытки;
	
	// В зависимости от вида обмена используется разный алгоритм анализа файла обмена.
	Если ЭтоОбменXDTO Тогда
		ФайлОбмена.Прочитать(); // Message.
		ФайлОбмена.Прочитать();  // Header начало.
		НачатьСчетОбъектов = Ложь;
		Пока ФайлОбмена.Прочитать() Цикл
			Если ФайлОбмена.ЛокальноеИмя = "Header" Тогда
				// Закончено чтение заголовка.
				НачатьСчетОбъектов = Истина;
				ФайлОбмена.Пропустить(); 
			ИначеЕсли ФайлОбмена.ЛокальноеИмя = "Confirmation" Тогда
				ФайлОбмена.Прочитать();
			ИначеЕсли ФайлОбмена.ЛокальноеИмя = "From" Тогда
				ФайлОбмена.Прочитать();
				Результат.From = ФайлОбмена.Значение;
				ФайлОбмена.Пропустить();
			ИначеЕсли ФайлОбмена.ЛокальноеИмя = "To" Тогда
				ФайлОбмена.Прочитать();
				Результат.To = ФайлОбмена.Значение;
				ФайлОбмена.Пропустить();
			ИначеЕсли ФайлОбмена.ЛокальноеИмя = "NewFrom" Тогда
				ФайлОбмена.Прочитать();
				Результат.NewFrom = ФайлОбмена.Значение;
				ФайлОбмена.Пропустить();
			ИначеЕсли НачатьСчетОбъектов 
				И ФайлОбмена.ТипУзла = ТипУзлаXML.НачалоЭлемента 
				И ФайлОбмена.ЛокальноеИмя <> "УдалениеОбъекта" 
				И ФайлОбмена.ЛокальноеИмя <> "Body" Тогда
				Результат.КоличествоОбъектовКЗагрузке = Результат.КоличествоОбъектовКЗагрузке + 1;
				ФайлОбмена.Пропустить();
			КонецЕсли;
		КонецЦикла;

	ИначеЕсли ЭтоОбменРИБ Тогда
		ФайлОбмена.Прочитать(); // Message.
		ФайлОбмена.Прочитать();  // Header начало.
		ФайлОбмена.Пропустить(); // Header конец.
		ФайлОбмена.Прочитать(); //Body начало.
		Пока ФайлОбмена.Прочитать() Цикл
			Если ФайлОбмена.ЛокальноеИмя = "Changes"
				ИЛИ ФайлОбмена.ЛокальноеИмя = "Data" Тогда
				Продолжить;
			ИначеЕсли СтрНайти(ФайлОбмена.ЛокальноеИмя, "Config") = 0 
				И СтрНайти(ФайлОбмена.ЛокальноеИмя, "Signature") = 0
				И СтрНайти(ФайлОбмена.ЛокальноеИмя, "Nodes") = 0
				И ФайлОбмена.ЛокальноеИмя <> "Parameters"
				И ФайлОбмена.ЛокальноеИмя <> "Body" Тогда
				Результат.КоличествоОбъектовКЗагрузке = Результат.КоличествоОбъектовКЗагрузке + 1;
			КонецЕсли;
			ФайлОбмена.Пропустить();
		КонецЦикла;	
	Иначе
		
		ФайлОбмена.Прочитать(); // Файл обмена.
		ФайлОбмена.Прочитать();  // ПравилаОбмена начало.
		ФайлОбмена.Пропустить(); // ПравилаОбмена конец.

		ФайлОбмена.Прочитать();  // Типы данных начало.
		ФайлОбмена.Пропустить(); // ТипыДанных конец.

		ФайлОбмена.Прочитать();  // Данные по обмену начало.
		ФайлОбмена.Пропустить(); // Данные по обмену конец.
		Пока ФайлОбмена.Прочитать() Цикл
			Если ФайлОбмена.ЛокальноеИмя = "Объект"
				ИЛИ ФайлОбмена.ЛокальноеИмя = "НаборЗаписейРегистра"
				ИЛИ ФайлОбмена.ЛокальноеИмя = "УдалениеОбъекта"
				ИЛИ ФайлОбмена.ЛокальноеИмя = "ИнформацияОРегистрацииОбъекта" Тогда
				Результат.КоличествоОбъектовКЗагрузке = Результат.КоличествоОбъектовКЗагрузке + 1;
			КонецЕсли;
			ФайлОбмена.Пропустить();
		КонецЦикла;
	КонецЕсли;
	ФайлОбмена.Закрыть();
	
	Возврат Результат;
КонецФункции

#КонецОбласти

#Область РаботаСОбъектомFTPСоединение

Функция FTPСоединение(Знач Настройки) Экспорт
	
	Возврат Новый FTPСоединение(
		Настройки.Сервер,
		Настройки.Порт,
		Настройки.ИмяПользователя,
		Настройки.ПарольПользователя,
		НастройкиПроксиСервера(Настройки.ЗащищенноеСоединение),
		Настройки.ПассивноеСоединение,
		Настройки.Таймаут,
		Настройки.ЗащищенноеСоединение);
	
КонецФункции

Функция FTPНастройкиСоединения(Знач Таймаут = 180) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Сервер", "");
	Результат.Вставить("Порт", 21);
	Результат.Вставить("ИмяПользователя", "");
	Результат.Вставить("ПарольПользователя", "");
	Результат.Вставить("ПассивноеСоединение", Ложь);
	Результат.Вставить("Таймаут", Таймаут);
	Результат.Вставить("ЗащищенноеСоединение", Неопределено);
	
	Возврат Результат;
КонецФункции

// Возвращает имя сервера и путь на сервере FTP, полученные из строки подключения к FTP-ресурсу.
//
// Параметры:
//  СтрокаПодключения - Строка - строка подключения к FTP-ресурсу.
// 
// Возвращаемое значение:
//  Структура - настройки подключения к FTP-ресурсу. Поля структуры:
//              Сервер - Строка - имя сервера.
//              Путь   - Строка - путь на сервере.
//
//  Пример (1):
// Результат = FTPИмяСервераИПуть("ftp://server");
// Результат.Сервер = "server";
// Результат.Путь = "/";
//
//  Пример (2):
// Результат = FTPИмяСервераИПуть("ftp://server/saas/obmen");
// Результат.Сервер = "server";
// Результат.Путь = "/saas/obmen/";
//
Функция FTPИмяСервераИПуть(Знач СтрокаПодключения) Экспорт
	
	Результат = Новый Структура("Сервер, Путь");
	СтрокаПодключения = СокрЛП(СтрокаПодключения);
	
	Если (ВРег(Лев(СтрокаПодключения, 6)) <> "FTP://"
		И ВРег(Лев(СтрокаПодключения, 7)) <> "FTPS://")
		ИЛИ СтрНайти(СтрокаПодключения, "@") <> 0 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Строка подключения к FTP-ресурсу не соответствует формату: ""%1""'"), СтрокаПодключения);
	КонецЕсли;
	
	ПараметрыПодключения = СтрРазделить(СтрокаПодключения, "/");
	
	Если ПараметрыПодключения.Количество() < 3 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В строке подключения к FTP-ресурсу не указано имя сервера: ""%1""'"), СтрокаПодключения);
	КонецЕсли;
	
	Результат.Сервер = ПараметрыПодключения[2];
	
	ПараметрыПодключения.Удалить(0);
	ПараметрыПодключения.Удалить(0);
	ПараметрыПодключения.Удалить(0);
	
	ПараметрыПодключения.Вставить(0, "@");
	
	Если Не ПустаяСтрока(ПараметрыПодключения.Получить(ПараметрыПодключения.ВГраница())) Тогда
		
		ПараметрыПодключения.Добавить("@");
		
	КонецЕсли;
	
	Результат.Путь = СтрСоединить(ПараметрыПодключения, "/");
	Результат.Путь = СтрЗаменить(Результат.Путь, "@", "");
	
	Возврат Результат;
КонецФункции

Функция ОткрытьПомощникСозданияОбменаДаннымиДляНастройкиПодчиненногоУзла() Экспорт
	
	Возврат Не ОбщегоНазначения.РазделениеВключено()
		И Не ЭтоАвтономноеРабочееМесто()
		И ЭтоПодчиненныйУзелРИБ()
		И Не Константы.НастройкаПодчиненногоУзлаРИБЗавершена.Получить();
	
КонецФункции

#КонецОбласти

#Область ПрофилиБезопасности

Функция ЗапросНаИспользованиеВнешнихРесурсовПриВключенииОбмена() Экспорт
	
	Запросы = Новый Массив();
	СформироватьЗапросыНаИспользованиеВнешнихРесурсов(Запросы);
	Возврат Запросы;
	
КонецФункции

Функция ЗапросНаОчисткуРазрешенийИспользованияВнешнихРесурсов() Экспорт
	
	Запросы = Новый Массив;
	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
	
	Для Каждого ИмяПланаОбмена Из ОбменДаннымиПовтИсп.ПланыОбменаБСП() Цикл
		
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	ПланОбмена.Ссылка КАК Узел
		|ИЗ
		|	ПланОбмена.[ИмяПланаОбмена] КАК ПланОбмена";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "[ИмяПланаОбмена]", ИмяПланаОбмена);
		
		Запрос = Новый Запрос;
		Запрос.Текст = ТекстЗапроса;
		
		Результат = Запрос.Выполнить();
		Выборка = Результат.Выбрать();
		
		Пока Выборка.Следующий() Цикл
			
			Запросы.Добавить(МодульРаботаВБезопасномРежиме.ЗапросНаОчисткуРазрешенийИспользованияВнешнихРесурсов(Выборка.Узел));
			
		КонецЦикла;
		
	КонецЦикла;
	
	Запросы.Добавить(МодульРаботаВБезопасномРежиме.ЗапросНаОчисткуРазрешенийИспользованияВнешнихРесурсов(
		ОбщегоНазначения.ИдентификаторОбъектаМетаданных(Метаданные.Константы.КаталогСообщенийОбменаДаннымиДляLinux)));
	Запросы.Добавить(МодульРаботаВБезопасномРежиме.ЗапросНаОчисткуРазрешенийИспользованияВнешнихРесурсов(
		ОбщегоНазначения.ИдентификаторОбъектаМетаданных(Метаданные.Константы.КаталогСообщенийОбменаДаннымиДляWindows)));
	
	Возврат Запросы;
	
КонецФункции

#КонецОбласти

#Область Прочее

Функция ИдентификаторЭтогоУзлаДляОбмена(УзелОбмена) Экспорт
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелОбмена);
	
	КодУзла = СокрЛП(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ПланыОбмена[ИмяПланаОбмена].ЭтотУзел(), "Код"));
	
	Если ОбменДаннымиПовтИсп.ЭтоУзелРазделенногоОбменаДаннымиБСП(УзелОбмена) Тогда

		ПрефиксыУзла = РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ПрефиксыУзла(УзелОбмена);
		ПрефиксЭтогоУзла = СокрЛП(ПрефиксыУзла.Префикс);
		
		Если Не ПустаяСтрока(ПрефиксЭтогоУзла)
			И СтрДлина(КодУзла) <= 2 Тогда
			// В качестве кода для целей идентификации при обмене использует префикс,
			// установленный при создании настройки подключения.
			КодУзла = ПрефиксЭтогоУзла;
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат КодУзла;
	
КонецФункции

Функция ИдентификаторУзлаКорреспондентаДляОбмена(УзелОбмена) Экспорт
	
	КодУзла = СокрЛП(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(УзелОбмена, "Код"));
	
	Если ОбменДаннымиПовтИсп.ЭтоУзелРазделенногоОбменаДаннымиБСП(УзелОбмена) Тогда
		ПрефиксыУзла = РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ПрефиксыУзла(УзелОбмена);
		
		Если СтрДлина(КодУзла) <= 2
			И Не ПустаяСтрока(ПрефиксыУзла.ПрефиксКорреспондента) Тогда
			// В качестве кода для целей идентификации при обмене использует префикс,
			// установленный при создании настройки подключения.
			КодУзла = СокрЛП(ПрефиксыУзла.ПрефиксКорреспондента);
		КонецЕсли;
	КонецЕсли;
	
	Возврат КодУзла;
	
КонецФункции

// Определяет является ли план обмена БСП разделенным.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя проверяемого плана обмена.
//
// Возвращаемое значение:
//  Тип - булево
//
Функция ЭтоРазделенныйПланОбменаБСП(Знач ИмяПланаОбмена) Экспорт
	
	Возврат ОбменДаннымиПовтИсп.РазделенныеПланыОбменаБСП().Найти(ИмяПланаОбмена) <> Неопределено;
	
КонецФункции

// Формирует выборку измененных данных для передачи их в тот или иной узел плана обмена.
// Если обращение к методу выполняется в активной транзакции, то вызывает исключение.
// См. описание метода ПланыОбменаМенеджер.ВыбратьИзменения() в синтакс-помощнике.
//
Функция ВыбратьИзменения(Знач Узел, Знач НомерСообщения, Знач ФильтрВыборки = Неопределено) Экспорт
	
	Если ТранзакцияАктивна() Тогда
		ВызватьИсключение НСтр("ru = 'Выборка изменений данных запрещена в активной транзакции.'");
	КонецЕсли;
	
	Возврат ПланыОбмена.ВыбратьИзменения(Узел, НомерСообщения, ФильтрВыборки);
КонецФункции

Функция СтруктураПараметровWS() Экспорт
	
	СтруктураПараметров = Новый Структура;
	СтруктураПараметров.Вставить("WSURLВебСервиса");
	СтруктураПараметров.Вставить("WSИмяПользователя");
	СтруктураПараметров.Вставить("WSПароль");
	
	Возврат СтруктураПараметров;
	
КонецФункции

Функция ТаблицаМонитораОбменаДанными(Знач ПланыОбмена, Знач ДополнительныеСвойстваПланаОбмена = "") Экспорт
	
	ТекстЗапроса = 
		"ВЫБРАТЬ
		|	ПланыОбмена.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	&ДополнительныеСвойстваПланаОбмена КАК ДополнительныеСвойстваПланаОбмена,
		|	ЕСТЬNULL(СостоянияОбменовДаннымиВыгрузка.РезультатВыполненияОбмена, 0) КАК РезультатПоследнейВыгрузкиДанных,
		|	ЕСТЬNULL(СостоянияОбменовДаннымиЗагрузка.РезультатВыполненияОбмена, 0) КАК РезультатПоследнейЗагрузкиДанных,
		|	ЕСТЬNULL(СостоянияОбменовДаннымиЗагрузка.ДатаНачала, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаНачалаПоследнейЗагрузки,
		|	ЕСТЬNULL(СостоянияОбменовДаннымиЗагрузка.ДатаОкончания, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаОкончанияПоследнейЗагрузки,
		|	ЕСТЬNULL(СостоянияОбменовДаннымиВыгрузка.ДатаНачала, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаНачалаПоследнейВыгрузки,
		|	ЕСТЬNULL(СостоянияОбменовДаннымиВыгрузка.ДатаОкончания, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаОкончанияПоследнейВыгрузки,
		|	ЕСТЬNULL(СостоянияУспешныхОбменовДаннымиЗагрузка.ДатаОкончания, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаОкончанияПоследнейУспешнойЗагрузки,
		|	ЕСТЬNULL(СостоянияУспешныхОбменовДаннымиВыгрузка.ДатаОкончания, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаОкончанияПоследнейУспешнойВыгрузки,
		|	ВЫБОР
		|		КОГДА СценарииСинхронизацииДанных.УзелИнформационнойБазы ЕСТЬ NULL
		|			ТОГДА 0
		|		ИНАЧЕ 1
		|	КОНЕЦ КАК РасписаниеНастроено,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.ВерсияКорреспондента, 0) КАК ВерсияКорреспондента,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.ПрефиксКорреспондента, """") КАК ПрефиксКорреспондента,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.НастройкаЗавершена, ЛОЖЬ) КАК НастройкаЗавершена,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.ПереходНаWS_Этап, 0) КАК ПереходНаWS_Этап,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.ВидТранспорта, """") КАК ВидТранспорта,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.СинхронизацияНедоступна, ЛОЖЬ) КАК СинхронизацияНедоступна,
		|	ВЫБОР
		|		КОГДА ЕСТЬNULL(СостоянияОбменовДаннымиВыгрузка.РезультатВыполненияОбмена, 0) = 0
		|				И ЕСТЬNULL(СостоянияОбменовДаннымиЗагрузка.РезультатВыполненияОбмена, 0) = 0
		|			ТОГДА ЛОЖЬ
		|		ИНАЧЕ ИСТИНА
		|	КОНЕЦ КАК ЕстьОшибки,
		|	ЕСТЬNULL(СообщенияДляСопоставленияДанных.ПолученоСообщениеДляСопоставленияДанных, ЛОЖЬ) КАК ПолученоСообщениеДляСопоставленияДанных,
		|	ЕСТЬNULL(СообщенияДляСопоставленияДанных.ДатаЗакладкиПоследнегоСообщения, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаСообщенияДляСопоставленияДанных
		|ИЗ
		|	ПланыОбменаКонфигурации КАК ПланыОбмена
		|		ЛЕВОЕ СОЕДИНЕНИЕ ОбщиеНастройкиУзловИнформационныхБаз КАК ОбщиеНастройкиУзловИнформационныхБаз
		|		ПО (ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы = ПланыОбмена.УзелИнформационнойБазы)
		|		ЛЕВОЕ СОЕДИНЕНИЕ СостоянияОбменовДаннымиЗагрузка КАК СостоянияОбменовДаннымиЗагрузка
		|		ПО (СостоянияОбменовДаннымиЗагрузка.УзелИнформационнойБазы = ПланыОбмена.УзелИнформационнойБазы)
		|		ЛЕВОЕ СОЕДИНЕНИЕ СостоянияОбменовДаннымиВыгрузка КАК СостоянияОбменовДаннымиВыгрузка
		|		ПО (СостоянияОбменовДаннымиВыгрузка.УзелИнформационнойБазы = ПланыОбмена.УзелИнформационнойБазы)
		|		ЛЕВОЕ СОЕДИНЕНИЕ СостоянияУспешныхОбменовДаннымиЗагрузка КАК СостоянияУспешныхОбменовДаннымиЗагрузка
		|		ПО (СостоянияУспешныхОбменовДаннымиЗагрузка.УзелИнформационнойБазы = ПланыОбмена.УзелИнформационнойБазы)
		|		ЛЕВОЕ СОЕДИНЕНИЕ СостоянияУспешныхОбменовДаннымиВыгрузка КАК СостоянияУспешныхОбменовДаннымиВыгрузка
		|		ПО (СостоянияУспешныхОбменовДаннымиВыгрузка.УзелИнформационнойБазы = ПланыОбмена.УзелИнформационнойБазы)
		|		ЛЕВОЕ СОЕДИНЕНИЕ СценарииСинхронизацииДанных КАК СценарииСинхронизацииДанных
		|		ПО (СценарииСинхронизацииДанных.УзелИнформационнойБазы = ПланыОбмена.УзелИнформационнойБазы)
		|		ЛЕВОЕ СОЕДИНЕНИЕ СообщенияДляСопоставленияДанных КАК СообщенияДляСопоставленияДанных
		|		ПО (СообщенияДляСопоставленияДанных.УзелИнформационнойБазы = ПланыОбмена.УзелИнформационнойБазы)
		|
		|УПОРЯДОЧИТЬ ПО
		|	ПланыОбмена.Наименование";
		
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДополнительныеСвойстваПланаОбмена КАК ДополнительныеСвойстваПланаОбмена,",
		ДополнительныеСвойстваПланаОбменаСтрокой(ДополнительныеСвойстваПланаОбмена));
		
	Запрос = Новый Запрос(ТекстЗапроса);	
	МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	
	УстановитьПривилегированныйРежим(Истина);
	ПолучитьСценарииОбменаДаннымиДляМонитора(МенеджерВременныхТаблиц);
	ПолучитьПланыОбменаДляМонитора(МенеджерВременныхТаблиц, ПланыОбмена, ДополнительныеСвойстваПланаОбмена);
	ПолучитьРезультатыОбменаДляМонитора(МенеджерВременныхТаблиц);
	ПолучитьСостоянияОбменовДанными(МенеджерВременныхТаблиц);
	ПолучитьСообщенияДляСопоставленияДанных(МенеджерВременныхТаблиц);
	ПолучитьОбщиеНастройкиУзловИнформационныхБаз(МенеджерВременныхТаблиц);
	
	НастройкиСинхронизации = Запрос.Выполнить().Выгрузить();
	
	НастройкиСинхронизации.Колонки.Добавить("ВариантОбменаДанными", Новый ОписаниеТипов("Строка"));
	НастройкиСинхронизации.Колонки.Добавить("ИмяПланаОбмена",       Новый ОписаниеТипов("Строка"));
	
	НастройкиСинхронизации.Колонки.Добавить("ДатаПоследнегоЗапуска", Новый ОписаниеТипов("Дата"));
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнегоЗапуска", Новый ОписаниеТипов("Строка"));
	
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнейЗагрузки", Новый ОписаниеТипов("Строка"));
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнейВыгрузки", Новый ОписаниеТипов("Строка"));
	
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнейУспешнойЗагрузки", Новый ОписаниеТипов("Строка"));
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнейУспешнойВыгрузки", Новый ОписаниеТипов("Строка"));
	
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыСообщенияДляСопоставленияДанных", Новый ОписаниеТипов("Строка"));
	
	НастройкиСинхронизации.Колонки.Добавить("ДоступенПереходНаWS", Новый ОписаниеТипов("Булево"));
	
	Для Каждого НастройкаСинхронизации Из НастройкиСинхронизации Цикл
		
		НастройкаСинхронизации.ДатаПоследнегоЗапуска = Макс(НастройкаСинхронизации.ДатаНачалаПоследнейЗагрузки,
			НастройкаСинхронизации.ДатаНачалаПоследнейВыгрузки);
		НастройкаСинхронизации.ПредставлениеДатыПоследнегоЗапуска = ОтносительнаяДатаСинхронизации(
			НастройкаСинхронизации.ДатаПоследнегоЗапуска);
		
		НастройкаСинхронизации.ПредставлениеДатыПоследнейЗагрузки = ОтносительнаяДатаСинхронизации(
			НастройкаСинхронизации.ДатаОкончанияПоследнейЗагрузки);
		НастройкаСинхронизации.ПредставлениеДатыПоследнейВыгрузки = ОтносительнаяДатаСинхронизации(
			НастройкаСинхронизации.ДатаОкончанияПоследнейВыгрузки);
		НастройкаСинхронизации.ПредставлениеДатыПоследнейУспешнойЗагрузки = ОтносительнаяДатаСинхронизации(
			НастройкаСинхронизации.ДатаОкончанияПоследнейУспешнойЗагрузки);
		НастройкаСинхронизации.ПредставлениеДатыПоследнейУспешнойВыгрузки = ОтносительнаяДатаСинхронизации(
			НастройкаСинхронизации.ДатаОкончанияПоследнейУспешнойВыгрузки);
		
		НастройкаСинхронизации.ПредставлениеДатыСообщенияДляСопоставленияДанных = ОтносительнаяДатаСинхронизации(
			МестноеВремя(НастройкаСинхронизации.ДатаСообщенияДляСопоставленияДанных));
		
		НастройкаСинхронизации.ВариантОбменаДанными = ВариантОбменаДанными(НастройкаСинхронизации.УзелИнформационнойБазы);
		НастройкаСинхронизации.ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(НастройкаСинхронизации.УзелИнформационнойБазы);
		
		Если ОбщегоНазначения.РазделениеВключено()
			И НастройкаСинхронизации.НастройкаЗавершена = Истина
			И ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(НастройкаСинхронизации.УзелИнформационнойБазы) = Истина
			И НастройкаСинхронизации.ВидТранспорта <> Перечисления.ВидыТранспортаСообщенийОбмена.WS
			И НастройкаСинхронизации.ВидТранспорта <> Перечисления.ВидыТранспортаСообщенийОбмена.WSПассивныйРежим Тогда
				
			НастройкаСинхронизации.ДоступенПереходНаWS = Истина;
				
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат НастройкиСинхронизации;
	
КонецФункции

Процедура ПроверитьВозможностьВыполненияОбменов(ПриложениеВИнтернете = Ложь) Экспорт
	
	Если Не ПравоДоступа("Просмотр", Метаданные.ОбщиеКоманды.Синхронизировать) Тогда
		
		Если ПриложениеВИнтернете Тогда
			
			ВызватьИсключение НСтр("ru = 'Недостаточно прав для синхронизации данных с приложением в Интернете.'");
			
		Иначе
			
			ВызватьИсключение НСтр("ru = 'Недостаточно прав для синхронизации данных.'");
			
		КонецЕсли;
		
	ИначеЕсли ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы()
		И Не ОбменДаннымиСлужебный.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРазрешена") Тогда
			
		Если ПриложениеВИнтернете Тогда
			
			ВызватьИсключение НСтр("ru = 'Приложение в Интернете находится в состоянии обновления.'");
			
		Иначе
			
			ВызватьИсключение НСтр("ru = 'Информационная база находится в состоянии обновления.'");
			
		КонецЕсли;
		
	ИначеЕсли ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
			
			МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
			НомерОбластиДанных = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса();
			
			УстановитьПривилегированныйРежим(Истина);
			
			Если МодульРаботаВМоделиСервиса.СтатусОбластиДанных(НомерОбластиДанных) <> Перечисления["СтатусыОбластейДанных"]["Используется"] Тогда
				
				ТекстИсключения = НСтр("ru = 'Синхронизация невозможна, потому что область данных отмечена как не рабочая.
					|Необходимо обратиться к администратору системы или в службу поддержки сервиса.'", ОбщегоНазначения.КодОсновногоЯзыка());
				
				ОбщиеНастройкиУзлов = РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.Выбрать();
				Пока ОбщиеНастройкиУзлов.Следующий() Цикл
					
					РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьАдминистративнуюОшибку(ОбщиеНастройкиУзлов.УзелИнформационнойБазы, ТекстИсключения);
					
				КонецЦикла;
				
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Ошибка, , , ТекстИсключения);
				ВызватьИсключение ТекстИсключения;
				
			КонецЕсли;
			
			УстановитьПривилегированныйРежим(Ложь);
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ПроверитьИспользованиеОбменаДанными(УстановитьИспользование = Ложь) Экспорт
	
	Если Не ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюДанных") Тогда
		
		Если Не ОбщегоНазначения.РазделениеВключено()
			И УстановитьИспользование
			И ПравоДоступа("Редактирование", Метаданные.Константы.ИспользоватьСинхронизациюДанных) Тогда
			
			Попытка
				Константы.ИспользоватьСинхронизациюДанных.Установить(Истина);
			Исключение
				ТекстСообщения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Ошибка,,,ТекстСообщения);
				ВызватьИсключение ТекстСообщения;
			КонецПопытки;
			
		Иначе
			ТекстСообщения = НСтр("ru = 'Синхронизация данных запрещена администратором.'");
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Ошибка,,,ТекстСообщения);
			ВызватьИсключение ТекстСообщения;
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Функция ПараметрыОбмена() Экспорт
	
	СтруктураПараметров = Новый Структура;
	
	СтруктураПараметров.Вставить("ВидТранспортаСообщенийОбмена", Неопределено);
	СтруктураПараметров.Вставить("ВыполнятьЗагрузку", Истина);
	СтруктураПараметров.Вставить("ВыполнятьВыгрузку", Истина);
	
	СтруктураПараметров.Вставить("ТолькоПараметры",     Ложь);
	
	СтруктураПараметров.Вставить("ДлительнаяОперацияРазрешена", Ложь);
	СтруктураПараметров.Вставить("ДлительнаяОперация", Ложь);
	СтруктураПараметров.Вставить("ИдентификаторОперации", "");
	СтруктураПараметров.Вставить("ИдентификаторФайла", "");
	СтруктураПараметров.Вставить("ПараметрыАутентификации", Неопределено);
	
	СтруктураПараметров.Вставить("СообщениеДляСопоставленияДанных", Ложь);
	
	СтруктураПараметров.Вставить("ИнтервалОжиданияНаСервере", 0);
	
	Возврат СтруктураПараметров;
	
КонецФункции

// Устарело. Использовать ОбменДаннымиВебСервис.ПолучитьWSПроксиПоПараметрамПодключения 
Функция ПолучитьWSПроксиПоПараметрамПодключения(
					СтруктураНастроек,
					СтрокаСообщенияОбОшибке = "",
					СообщениеПользователю = "",
					ДелатьКонтрольныйВызов = Ложь) Экспорт
	
	WSПрокси = ОбменДаннымиВебСервис.ПолучитьWSПроксиПоПараметрамПодключения(
					СтруктураНастроек,
					СтрокаСообщенияОбОшибке,
					СообщениеПользователю,
					ДелатьКонтрольныйВызов);
	
	Возврат WSПрокси;
	
КонецФункции

// Определяет, входит ли план обмена в список планов обмена, которые используют обмен данными по формату XDTO.
//
// Параметры:
//  ПланОбмена - ПланОбменаСсылка - ссылка на узел плана обмена или имя плана обмена.
//
// Возвращаемое значение:
//  Булево - Истина, если план обмена используется для обмена данными по формату XDTO.
//
Функция ЭтоПланОбменаXDTO(ПланОбмена) Экспорт
	
	Возврат ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(ПланОбмена);
	
КонецФункции

// Выполняет действия по удалению настройки синхронизации данных.
// 
// Параметры:
//   УзелИнформационнойБазы - ПланОбменаСсылка - ссылка на удаляемый узел плана обмена.
// 
Процедура УдалитьНастройкуСинхронизации(УзелИнформационнойБазы) Экспорт
	
	ПроверитьВозможностьАдминистрированияОбменов();
	
	Если Не ОбщегоНазначения.СсылкаСуществует(УзелИнформационнойБазы) Тогда
		Возврат;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(УзелИнформационнойБазы));
		ЭлементБлокировки.УстановитьЗначение("Ссылка", УзелИнформационнойБазы);
		Блокировка.Заблокировать();
		
		ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища(УзелИнформационнойБазы);
		
		ЗаблокироватьДанныеДляРедактирования(УзелИнформационнойБазы);
		ОбъектУзла = УзелИнформационнойБазы.ПолучитьОбъект();
		ОбъектУзла.ДополнительныеСвойства.Вставить("УдалениеНастройкиСинхронизации");
		ОбъектУзла.Удалить();
		
		ИмяПланаОбмена = ОбъектУзла.Метаданные().Имя;
		ОбменДаннымиКонтрольЗацикливания.ОбновитьКонтур(ИмяПланаОбмена);
		ОбменДаннымиКонтрольЗацикливания.ПроверитьЗацикливание(ИмяПланаОбмена, "УдалениеУзла");

		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Выполняет действия по удалению настройки синхронизации данных с главным узлом РИБ.
// 
// Параметры:
//   УзелИнформационнойБазы - ПланОбменаСсылка - ссылка на главный узел.
// 
Процедура УдалитьНастройкиСинхронизацииСГлавнымУзломРИБ(УзелИнформационнойБазы) Экспорт
	
	УдалитьНастройкуСинхронизации(УзелИнформационнойБазы);
	
	НастройкаПодчиненногоУзлаРИБЗавершена = Константы.НастройкаПодчиненногоУзлаРИБЗавершена.СоздатьМенеджерЗначения();
	НастройкаПодчиненногоУзлаРИБЗавершена.Прочитать();
	Если НастройкаПодчиненногоУзлаРИБЗавершена.Значение Тогда
		НастройкаПодчиненногоУзлаРИБЗавершена.Значение = Ложь;
		ОбновлениеИнформационнойБазы.ЗаписатьДанные(НастройкаПодчиненногоУзлаРИБЗавершена);
	КонецЕсли;
	
КонецПроцедуры

// Устанавливает значение параметра "Загрузка" для свойства объекта "ОбменДанными".
//
// Параметры:
//  Объект - Произвольный - объект, для которого устанавливается свойство.
//  Значение - Булево - значение устанавливаемого свойства "Загрузка".
//  ОтправкаНазад - Булево - признак необходимости регистрации данных к обратной отправке.
//  УзелОбмена - ПланОбменаСсылка - признак необходимости регистрации данных к обратной отправке.
//
Процедура УстановитьОбменДаннымиЗагрузка(Объект, Значение = Истина, ОтправкаНазад = Ложь, УзелОбмена = Неопределено) Экспорт
	
	Объект.ОбменДанными.Загрузка = Значение;
	
	Если Не ОтправкаНазад
		И УзелОбмена <> Неопределено
		И НЕ УзелОбмена.Пустая() Тогда
	
		ТипЗначенияОбъекта = ТипЗнч(Объект);
		ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗначенияОбъекта);
		
		Если Метаданные.ПланыОбмена[УзелОбмена.Метаданные().Имя].Состав.Содержит(ОбъектМетаданных) Тогда
			Объект.ОбменДанными.Отправитель = УзелОбмена;
		КонецЕсли;
	
	КонецЕсли;
	
КонецПроцедуры

Функция НазначениеПланаОбмена(ИмяПланаОбмена) Экспорт
	
	Возврат ОбменДаннымиПовтИсп.НазначениеПланаОбмена(ИмяПланаОбмена);
	
КонецФункции

// Процедура удаления существующих движений документа при перепроведении (отмене проведения).
//
// Параметры:
//   ДокументОбъект - ДокументОбъект - документ, движения которого требуется удалить.
//
Процедура УдалитьДвиженияУДокумента(ДокументОбъект) Экспорт
	
	МассивОбрабатываемыхСтрокТаблицыДвижений = Новый Массив;
	
	ВставитьДополнительныйПараметрУдаленияДвижений = 
		ДокументОбъект.ДополнительныеСвойства.Свойство("СинхронизацияДанныхЧерезУниверсальныйФорматУдалениеДвижений")
			И (ДокументОбъект.ДополнительныеСвойства.СинхронизацияДанныхЧерезУниверсальныйФорматУдалениеДвижений = Истина);
	
	// Получение списка регистров, по которым существуют движения.
	ТаблицаДвижений = ОпределитьНаличиеДвиженийПоДокументу(ДокументОбъект.Ссылка);
	
	Для Каждого СтрокаДвижения Из ТаблицаДвижений Цикл
		// Имя регистра передается как значение, полученное с помощью
		// функции ПолноеИмя() метаданных регистра.
		ПолноеИмяРегистра = СтрокаДвижения.ИмяТаблицыРегистра;
		
		МассивОбрабатываемыхСтрокТаблицыДвижений.Добавить(СтрокаДвижения);
		
		Набор = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяРегистра).СоздатьНаборЗаписей();
		
		Если Не ПравоДоступа("Изменение", Набор.Метаданные()) Тогда
			// Отсутствуют права на всю таблицу регистра.
			ТекстИсключения = НСтр("ru = 'Нарушение прав доступа: %1'");
			ТекстИсключения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстИсключения, ПолноеИмяРегистра);
			ВызватьИсключение ТекстИсключения;
		КонецЕсли;
		
		ОбменДаннымиСлужебный.УстановитьЗначениеЭлементаОтбора(Набор.Отбор, "Регистратор", ДокументОбъект.Ссылка);
		
		// Набор не записывается сразу, чтобы не откатывать транзакцию, если впоследствии
		// выяснится, что на один из регистров не хватает прав.
		СтрокаДвижения.НаборЗаписей = Набор;
		
	КонецЦикла;
	
	ПроверкаДатЗапретаОтключена = ПроверкаДатЗапретаОтключена();
	ОтключитьПроверкуДатЗапрета(Истина);
	Попытка
		Для Каждого СтрокаДвижения Из МассивОбрабатываемыхСтрокТаблицыДвижений Цикл
			Попытка
				
				Набор = СтрокаДвижения.НаборЗаписей; // РегистрНакопленияНаборЗаписей и т.п.
				Если ВставитьДополнительныйПараметрУдаленияДвижений Тогда
					
					Набор.ДополнительныеСвойства.Вставить("СинхронизацияДанныхЧерезУниверсальныйФорматУдалениеДвижений", Истина);
					
				КонецЕсли;
				
				Набор.Записать();
				
			Исключение
				
				// Возможно "сработало" ограничение на уровне записей или подсистема даты запрета изменения.
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Операция не выполнена: %1
					|%2'"),
					СтрокаДвижения.ИмяТаблицыРегистра,
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
					
			КонецПопытки;
		КонецЦикла;
	Исключение
		ОтключитьПроверкуДатЗапрета(ПроверкаДатЗапретаОтключена);
		ВызватьИсключение;
	КонецПопытки;
	ОтключитьПроверкуДатЗапрета(ПроверкаДатЗапретаОтключена);
	
	Для Каждого Движение Из ДокументОбъект.Движения Цикл
		Если Движение.Количество() > 0 Тогда
			Движение.Очистить();
		КонецЕсли;
	КонецЦикла;
	
	// Удаление записей регистрации из всех последовательностей.
	Если ДокументОбъект.Метаданные().ЗаполнениеПоследовательностей = Метаданные.СвойстваОбъектов.ЗаполнениеПоследовательностей.ЗаполнятьАвтоматически Тогда
		Для Каждого НаборЗаписейПоследовательности Из ДокументОбъект.ПринадлежностьПоследовательностям Цикл
			Если НаборЗаписейПоследовательности.Количество() > 0 Тогда
				НаборЗаписейПоследовательности.Очистить();
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

КонецПроцедуры

// Возвращает признак необходимости загрузки сообщения обмена данными.
//
// Возвращаемое значение:
//   Булево - если Истина, то необходимо загрузить сообщение; Ложь - нет.
//
Функция ЗагрузитьСообщениеОбменаДанными() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат Константы.ЗагрузитьСообщениеОбменаДанными.Получить();
	
КонецФункции

// Инициализирует колонки таблицы правил регистрации по свойствам.
//
//  Возвращаемое значение:
//    ДеревоЗначений
//
Функция ИнициализацияТаблицыОтборПоСвойствамПланаОбмена() Экспорт
	
	Возврат ОбменДаннымиПовтИсп.ИнициализацияТаблицыОтборПоСвойствамПланаОбмена();

КонецФункции

// Инициализирует колонки таблицы правил регистрации по свойствам.
//
//  Возвращаемое значение:
//    ДеревоЗначений
//
Функция ИнициализацияТаблицыОтборПоСвойствамОбъекта() Экспорт
	
	Возврат ОбменДаннымиПовтИсп.ИнициализацияТаблицыОтборПоСвойствамОбъекта();

КонецФункции

#КонецОбласти

#Область ОбработчикиСобытийПодсистемКонфигурации

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.Процедура = "ОбменДаннымиСервер.УстановитьКоличествоЭлементовВТранзакцииЗагрузкиДанныхПоУмолчанию";
	Обработчик.ОбщиеДанные = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.ОбщиеДанные = Истина;
	Обработчик.УправлениеОбработчиками = Истина;
	Обработчик.Версия = "*";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.Процедура = "ОбменДаннымиСервер.ЗаполнитьОбработчикиРазделенныхДанных";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "*";
	Обработчик.Процедура = "ОбменДаннымиСервер.УстановитьКодыПредопределенныхУзлов";
	Обработчик.РежимВыполнения = "Оперативно";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "*";
	Обработчик.Процедура = "ОбменДаннымиСервер.НастроитьАрхивированиеСообщенийАРМ";
	Обработчик.РежимВыполнения = "Оперативно";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "2.4.1.1";
	Обработчик.Процедура = "ОбменДаннымиСервер.УдалитьРольНастройкаСинхронизацииДанных";
	Обработчик.РежимВыполнения = "Оперативно";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.2.172";
	Обработчик.Процедура = "ОбменДаннымиСервер.УстановитьКоличествоЭлементовВТранзакцииЗагрузкиДанныхПоУмолчанию";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.0.1.91";
	Обработчик.Комментарий =
		НСтр("ru = 'Перенос настроек подключения обменов данными в новый регистр ""Настройки транспорта обмена данными"".'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("8d5f1092-f569-4c03-aca9-65625809b853");
	Обработчик.Процедура = "РегистрыСведений.НастройкиТранспортаОбменаДанными.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ЧитаемыеОбъекты = "РегистрСведений.УдалитьНастройкиТранспортаОбмена";
	Обработчик.ИзменяемыеОбъекты = "РегистрСведений.УдалитьНастройкиТранспортаОбмена,РегистрСведений.НастройкиТранспортаОбменаДанными";
	Обработчик.ОчередьОтложеннойОбработки = 1;
	Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = Истина;
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.НастройкиТранспортаОбменаДанными.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.БлокируемыеОбъекты = "РегистрСведений.УдалитьНастройкиТранспортаОбмена,РегистрСведений.НастройкиТранспортаОбменаДанными";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.0.1.91";
	Обработчик.Комментарий =
		НСтр("ru = 'Первоначальное заполнение настроек обмена данными XDTO.'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("2ea5ec7e-547b-4e8b-9c3f-d2d8652c8cdf");
	Обработчик.Процедура = "РегистрыСведений.НастройкиОбменаДаннымиXDTO.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ЧитаемыеОбъекты = "РегистрСведений.НастройкиОбменаДаннымиXDTO";
	Обработчик.ИзменяемыеОбъекты = "РегистрСведений.НастройкиОбменаДаннымиXDTO";
	Обработчик.ОчередьОтложеннойОбработки = 1;
	Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = Истина;
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.НастройкиОбменаДаннымиXDTO.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.БлокируемыеОбъекты = "РегистрСведений.НастройкиОбменаДаннымиXDTO";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.0.1.281";
	Обработчик.Комментарий =
		НСтр("ru = 'Заполнение вспомогательных настроек обмена данными в регистре ""Общие настройки узлов информационных баз"".'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("e1cd64f1-3df9-4ea6-8076-1ba0627ba104");
	Обработчик.Процедура = "РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ЧитаемыеОбъекты = "РегистрСведений.ОбщиеНастройкиУзловИнформационныхБаз";
	Обработчик.ИзменяемыеОбъекты = "РегистрСведений.ОбщиеНастройкиУзловИнформационныхБаз";
	Обработчик.ОчередьОтложеннойОбработки = 1;
	Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = Истина;
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.БлокируемыеОбъекты = "РегистрСведений.ОбщиеНастройкиУзловИнформационныхБаз";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.1.22";
	Обработчик.Комментарий =
		НСтр("ru = 'Перенос результатов выполнения обменов данными в новый регистр.'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("012c28d7-bbe8-494f-87f7-620ffe5c99e2");
	Обработчик.Процедура = "РегистрыСведений.РезультатыОбменаДанными.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ЧитаемыеОбъекты = "РегистрСведений.УдалитьРезультатыОбменаДанными";
	Обработчик.ИзменяемыеОбъекты = "РегистрСведений.УдалитьРезультатыОбменаДанными,РегистрСведений.РезультатыОбменаДанными";
	Обработчик.ОчередьОтложеннойОбработки = 1;
	Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = Истина;
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.БлокируемыеОбъекты = "РегистрСведений.УдалитьРезультатыОбменаДанными,РегистрСведений.РезультатыОбменаДанными";
	
КонецПроцедуры

// См. ОбновлениеИнформационнойБазыБСП.ПередОбновлениемИнформационнойБазы.
Процедура ПередОбновлениемИнформационнойБазы(ПриЗапускеКлиентскогоПриложения, Перезапустить) Экспорт
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;	
	КонецЕсли;
	
	Если НЕ ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы() Тогда
		ВыполнитьСинхронизациюПриОтсутствииОбновленияИнформационнойБазы(ПриЗапускеКлиентскогоПриложения, Перезапустить);
	Иначе	
		ЗагрузитьСообщениеПередОбновлениемИнформационнойБазы();
	КонецЕсли;

КонецПроцедуры

// См. ОбновлениеИнформационнойБазыБСП.ПослеОбновленияИнформационнойБазы.
Процедура ПослеОбновленияИнформационнойБазы() Экспорт
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	РегистрыСведений.ОбработчикиСобытийСинхронизацииДанных.ЗарегистрироватьОбновлениеДанныхИнформационнойБазы();
	
	ВыгрузитьСообщениеПослеОбновленияИнформационнойБазы();
	
КонецПроцедуры	

// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами.
Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт
	Объекты.Вставить(Метаданные.Справочники.СценарииОбменовДанными.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке");
КонецПроцедуры

// См. РаботаВМоделиСервисаПереопределяемый.ПриВключенииРазделенияПоОбластямДанных.
Процедура ПриВключенииРазделенияПоОбластямДанных() Экспорт
	
	Если Не Константы.ИспользоватьСинхронизациюДанных.Получить() Тогда
		Константы.ИспользоватьСинхронизациюДанных.Установить(Истина);
	КонецЕсли;
	
	ВыполнитьОбновлениеПравилДляОбменаДанными();
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса.
Процедура ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики) Экспорт
	
	Обработчики.Вставить("РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском", "ОбменДаннымиСлужебный.УстановкаПараметровСеанса");
	Обработчики.Вставить("ДатаОбновленияПовторноИспользуемыхЗначенийМРО",    "ОбменДаннымиСлужебный.УстановкаПараметровСеанса");
	Обработчики.Вставить("ПравилаРегистрацииОбъектов",                       "ОбменДаннымиСлужебный.УстановкаПараметровСеанса");
	Обработчики.Вставить("ПаролиСинхронизацииДанных",                        "ОбменДаннымиСлужебный.УстановкаПараметровСеанса");
	Обработчики.Вставить("ПриоритетныеДанныеОбмена",                         "ОбменДаннымиСлужебный.УстановкаПараметровСеанса");
	Обработчики.Вставить("ОшибкаРасхожденияВерсийПриПолученииДанных",        "ОбменДаннымиСлужебный.УстановкаПараметровСеанса");
	Обработчики.Вставить("ПараметрыСеансаСинхронизацииДанных",               "ОбменДаннымиСлужебный.УстановкаПараметровСеанса");
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов.
Процедура ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов(Знач СтруктураПоддерживаемыхВерсий) Экспорт
	
	МассивВерсий = Новый Массив;
	МассивВерсий.Добавить("2.0.1.6");
	МассивВерсий.Добавить("2.1.1.7");
	МассивВерсий.Добавить("3.0.1.1");
	МассивВерсий.Добавить("3.0.2.1");
	МассивВерсий.Добавить("3.0.2.2");
	СтруктураПоддерживаемыхВерсий.Вставить("ОбменДанными", МассивВерсий);
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПараметровРаботыКлиентаПриЗапуске.
Процедура ПриДобавленииПараметровРаботыКлиентаПриЗапуске(Параметры) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Параметры.Вставить("ИмяПланаОбменаРИБ", ?(ЭтоПодчиненныйУзелРИБ(), ГлавныйУзел().Метаданные().Имя, ""));
	Параметры.Вставить("ГлавныйУзел", ГлавныйУзел());
	
	Если ОткрытьПомощникСозданияОбменаДаннымиДляНастройкиПодчиненногоУзла() Тогда
		
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Взаимодействия") Тогда
			МодульВзаимодействия = ОбщегоНазначения.ОбщийМодуль("Взаимодействия");
			МодульВзаимодействия.ВыполнитьПолныйПерерасчетСостояний();
		КонецЕсли;
		
		Параметры.Вставить("ОткрытьПомощникСозданияОбменаДаннымиДляНастройкиПодчиненногоУзла");
		
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Ложь);
	
	Если Параметры.Свойство("ОткрытьПомощникСозданияОбменаДаннымиДляНастройкиПодчиненногоУзла") Тогда
		
		ЭтотУзел = ПланыОбмена[Параметры.ИмяПланаОбменаРИБ].ЭтотУзел();
		Параметры.Вставить("ИдентификаторНастройкиУзлаРИБ", СохраненныйВариантНастройкиУзлаПланаОбмена(ЭтотУзел));
		
	КонецЕсли;
	
	Если Не Параметры.Свойство("ОткрытьПомощникСозданияОбменаДаннымиДляНастройкиПодчиненногоУзла")
		И ПравоДоступа("Просмотр", Метаданные.ОбщиеКоманды.Синхронизировать) Тогда
		
		Параметры.Вставить("ПроверитьНеобходимостьОбновленияКонфигурацииПодчиненногоУзла");
	КонецЕсли;
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПараметровРаботыКлиента.
Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Параметры.Вставить("ГлавныйУзел", ГлавныйУзел());
	
КонецПроцедуры

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииПоставляемыхПрофилейГруппДоступа
Процедура ПриЗаполненииПоставляемыхПрофилейГруппДоступа(ОписанияПрофилей, ПараметрыОбновления) Экспорт
	
	// Профиль "Синхронизация данных с другими программами".
	ОписаниеПрофиля = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом").НовоеОписаниеПрофиляГруппДоступа();
	ОписаниеПрофиля.Родитель      = "ДополнительныеПрофили";
	ОписаниеПрофиля.Идентификатор = ПрофильДоступаСинхронизацияДанныхСДругимиПрограммами();
	ОписаниеПрофиля.Наименование =
		НСтр("ru = 'Синхронизация данных с другими программами'", ОбщегоНазначения.КодОсновногоЯзыка());
	ОписаниеПрофиля.Описание =
		НСтр("ru = 'Дополнительно назначается тем пользователям, которым должны быть доступны средства
		           |для мониторинга и синхронизации данных с другими программами.'");
	
	// Основные возможности профиля.
	РолиПрофиля = СтрРазделить(РолиПрофиляДоступаСинхронизацияДанныхСДругимиПрограммами(), ",");
	Для Каждого Роль Из РолиПрофиля Цикл
		ОписаниеПрофиля.Роли.Добавить(СокрЛП(Роль));
	КонецЦикла;
	ОписанияПрофилей.Добавить(ОписаниеПрофиля);
	
КонецПроцедуры

// Параметры:
//   ТекущиеДела - см. ТекущиеДелаСервер.ТекущиеДела.
//
Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт
	
	Если Не ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюДанных") Тогда
		Возврат;
	КонецЕсли;
	
	ПриЗаполненииСпискаТекущихДелПредупрежденияСинхронизации(ТекущиеДела);
	ПриЗаполненииСпискаТекущихДелНеобходимоОбновление(ТекущиеДела);
	ПриЗаполненииСпискаТекущихДелПроверитьСовместимостьСТекущейВерсией(ТекущиеДела);
	ПриЗаполненииСпискаТекущихДелПроверитьЗацикливание(ТекущиеДела);
	
КонецПроцедуры

// См. РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий
Процедура ПриОпределенииНастроекРегламентныхЗаданий(Настройки) Экспорт
	Зависимость = Настройки.Добавить();
	Зависимость.РегламентноеЗадание = Метаданные.РегламентныеЗадания.УдалениеНеактуальнойИнформацииСинхронизации;
	Зависимость.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ИспользоватьСинхронизациюДанных;
	Зависимость.РаботаетСВнешнимиРесурсами = Истина;
	
	Зависимость = Настройки.Добавить();
	Зависимость.РегламентноеЗадание = Метаданные.РегламентныеЗадания.СинхронизацияДанных;
	Зависимость.РаботаетСВнешнимиРесурсами = Истина;
	Зависимость.Параметризуется = Истина;
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.
Процедура ПриДобавленииПереименованийОбъектовМетаданных(Итог) Экспорт
	
	Библиотека = "СтандартныеПодсистемы";
	
	ОбщегоНазначения.ДобавитьПереименование(
		Итог, "2.1.2.5", "Роль.ВыполнениеОбменовДанными", "Роль.ВыполнениеСинхронизацииДанных", Библиотека);
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.
Процедура ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаСсылок) Экспорт
	
	ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.РезультатыОбменаДанными.ПолноеИмя());
	
КонецПроцедуры

// См. РаботаВБезопасномРежимеПереопределяемый.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам.
Процедура ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений) Экспорт
	
	Если Не Константы.ИспользоватьСинхронизациюДанных.Получить() Тогда
		Возврат;
	КонецЕсли;
	
	СформироватьЗапросыНаИспользованиеВнешнихРесурсов(ЗапросыРазрешений);
	
КонецПроцедуры

// См. ИнтеграцияПодсистемБСП.ПриРегистрацииМенеджеровВнешнихМодулей
Процедура ПриРегистрацииМенеджеровВнешнихМодулей(Менеджеры) Экспорт
	
	Менеджеры.Добавить(ОбменДаннымиСервер);
	
КонецПроцедуры

// См. ОчередьЗаданийПереопределяемый.ПриОпределенииПсевдонимовОбработчиков.
Процедура ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам) Экспорт
	
	СоответствиеИменПсевдонимам.Вставить("ОбменДаннымиСервер.ВыполнитьОбменДаннымиСВнешнейСистемой");
	СоответствиеИменПсевдонимам.Вставить(Метаданные.РегламентныеЗадания.СинхронизацияДанных.ИмяМетода);
	
КонецПроцедуры

// См. ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовИсключаемыхИзПроверки.
Процедура ПриОпределенииОбъектовИсключаемыхИзПроверки(Объекты) Экспорт
	Объекты.Добавить(Метаданные.РегистрыСведений.СоответствияОбъектовИнформационныхБаз);
КонецПроцедуры

#КонецОбласти

#Область ФункцииСвойства

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииЗагрузкаПравилДляОбменаДанными() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными.Загрузка правил'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииСозданиеОбменаДанными() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными.Создание обмена данными'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииУдалениеОбменаДанными() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными.Удаление обмена данными'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииРегистрацияДанныхДляНачальнойВыгрузки() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными.Регистрация данных для начальной выгрузки'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииВыгрузкаДанныхДляСопоставления() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными.Выгрузка данных для сопоставления'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииУдалениеВременногоФайла() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными.Удаление временного файла'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииОбменДанными() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииВыгрузкаДанныхВСервисПередачиФайлов() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными.Сервис передачи файлов.Выгрузка данных'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрацииЗагрузкаДанныхИзСервисаПередачиФайлов() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными.Сервис передачи файлов.Загрузка данных'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

#КонецОбласти

#Область ИнициализацияСтруктурыНастроекОбмена

Функция ПсевдонимПредопределенногоУзла(УзелКорреспондента) Экспорт
	
	Если Не ЭтоПланОбменаXDTO(УзелКорреспондента) Тогда
		Возврат "";
	КонецЕсли;
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	ПсевдонимыПредопределенныхУзлов.КодУзла КАК КодУзла
	|ИЗ
	|	РегистрСведений.ПсевдонимыПредопределенныхУзлов КАК ПсевдонимыПредопределенныхУзлов
	|ГДЕ
	|	ПсевдонимыПредопределенныхУзлов.Корреспондент = &УзелИнформационнойБазы");
	Запрос.УстановитьПараметр("УзелИнформационнойБазы", УзелКорреспондента);
	
	ПсевдонимПредопределенногоУзла = "";
	
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		ПсевдонимПредопределенногоУзла = СокрЛП(Выборка.КодУзла);
	КонецЕсли;
	
	Возврат ПсевдонимПредопределенногоУзла;
	
КонецФункции

Функция НастройкиОбменаДляУзлаИнформационнойБазы(
	УзелИнформационнойБазы,
	ДействиеПриОбмене,
	ВидТранспортаСообщенийОбмена,
	ИспользоватьНастройкиТранспорта = Истина) Экспорт
	
	// Возвращаемое значение функции.
	СтруктураНастроекОбмена = СтруктураНастроекОбменаБазовая();
	
	СтруктураНастроекОбмена.УзелИнформационнойБазы = УзелИнформационнойБазы;
	СтруктураНастроекОбмена.ДействиеПриОбмене      = ДействиеПриОбмене;
	СтруктураНастроекОбмена.ВидТранспортаОбмена    = ВидТранспортаСообщенийОбмена;
	СтруктураНастроекОбмена.ЭтоОбменВРИБ           = ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(УзелИнформационнойБазы);
	
	ВыполнитьИнициализациюСтруктурыНастроекОбменаДляУзлаИнформационнойБазы(СтруктураНастроекОбмена, ИспользоватьНастройкиТранспорта);
	
	УстановитьНастройкиРежимаОтладкиДляСтруктуры(СтруктураНастроекОбмена);
	
	// Проверяем структуру настроек на валидность значений для выполнения обмена. Ошибки фиксируем в ЖР.
	ВыполнитьПроверкуСтруктурыОбменаНаВалидность(СтруктураНастроекОбмена, ИспользоватьНастройкиТранспорта);
	
	// Если настройки содержат ошибки, то выходим.
	Если СтруктураНастроекОбмена.Отказ Тогда
		Возврат СтруктураНастроекОбмена;
	КонецЕсли;
	
	Если ИспользоватьНастройкиТранспорта Тогда
		
		// Инициализируем обработку транспорта сообщений обмена.
		ВыполнитьИнициализациюОбработкиТранспортаСообщенийОбмена(СтруктураНастроекОбмена);
		
	КонецЕсли;
	
	// Инициализируем обработку обмена данными.
	Если СтруктураНастроекОбмена.ЭтоОбменВРИБ Тогда
		
		ВыполнитьИнициализациюОбработкиОбмена(СтруктураНастроекОбмена);
		
	ИначеЕсли СтруктураНастроекОбмена.ОбменПоПравиламКонвертацииОбъектов Тогда
		
		ВыполнитьИнициализациюОбработкиОбменаПоПравиламКонвертации(СтруктураНастроекОбмена);
		
	КонецЕсли;
	
	Возврат СтруктураНастроекОбмена;
КонецФункции

#КонецОбласти

#Область ДляРаботыЧерезВнешнееСоединение

Функция ПараметрыОбменаДаннымиЧерезФайлИлиСтроку() Экспорт
	
	СтруктураПараметров = Новый Структура;
	
	СтруктураПараметров.Вставить("УзелИнформационнойБазы");
	СтруктураПараметров.Вставить("ПолноеИмяФайлаСообщенияОбмена", "");
	СтруктураПараметров.Вставить("ДействиеПриОбмене");
	СтруктураПараметров.Вставить("ИмяПланаОбмена", "");
	СтруктураПараметров.Вставить("КодУзлаИнформационнойБазы", "");
	СтруктураПараметров.Вставить("СообщениеОбмена", "");
	СтруктураПараметров.Вставить("ДатаНачалаОперации");
	
	Возврат СтруктураПараметров;
	
КонецФункции

Процедура ВыполнитьОбменДаннымиДляУзлаИнформационнойБазыЧерезФайлИлиСтроку(ПараметрыОбмена) Экспорт
	
	ПроверитьВозможностьВыполненияОбменов();
	
	ПроверитьИспользованиеОбменаДанными();
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если ПараметрыОбмена.УзелИнформационнойБазы = Неопределено Тогда
		
		ИмяПланаОбмена = ПараметрыОбмена.ИмяПланаОбмена;
		КодУзлаИнформационнойБазы = ПараметрыОбмена.КодУзлаИнформационнойБазы;
		
		ПараметрыОбмена.УзелИнформационнойБазы = ПланыОбмена[ИмяПланаОбмена].НайтиПоКоду(КодУзлаИнформационнойБазы);
			
		Если ПараметрыОбмена.УзелИнформационнойБазы.Пустая()
			И ЭтоПланОбменаXDTO(ИмяПланаОбмена) Тогда
			ОшибкаПерехода = Ложь;
			НастройкаСинхронизацииЧерезУФ = ПланыОбмена[ИмяПланаОбмена].ПереходНаСинхронизациюЧерезУниверсальныйФорматИнтернет(
				КодУзлаИнформационнойБазы, ОшибкаПерехода);
			Если ЗначениеЗаполнено(НастройкаСинхронизацииЧерезУФ) Тогда
				ПараметрыОбмена.УзелИнформационнойБазы = НастройкаСинхронизацииЧерезУФ;
			ИначеЕсли ОшибкаПерехода Тогда
				СтрокаСообщенияОбОшибке = НСтр("ru = 'Не удалось выполнить переход на синхронизацию данных через универсальный формат.'");
				ВызватьИсключение СтрокаСообщенияОбОшибке;
			КонецЕсли;
		КонецЕсли;
		
		Если ПараметрыОбмена.УзелИнформационнойБазы.Пустая() Тогда
			СтрокаСообщенияОбОшибке = НСтр("ru = 'Узел плана обмена %1 с кодом %2 не найден.'");
			СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщенияОбОшибке, ИмяПланаОбмена, КодУзлаИнформационнойБазы);
			ВызватьИсключение СтрокаСообщенияОбОшибке;
		КонецЕсли;
		
	КонецЕсли;
	
	ВыполнитьОбновлениеНастроекОбмена(ПараметрыОбмена.УзелИнформационнойБазы);
	
	Если Не НастройкаСинхронизацииЗавершена(ПараметрыОбмена.УзелИнформационнойБазы) Тогда
		
		ПредставлениеПрограммы = ?(ОбщегоНазначения.РазделениеВключено(),
			Метаданные.Синоним, ОбменДаннымиПовтИсп.ИмяЭтойИнформационнойБазы());
			
		ДанныеКорреспондента = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ПараметрыОбмена.УзелИнформационнойБазы,
			"Код, Наименование");
		
		СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В ""%1"" настройка синхронизации данных с ""%2"" (идентификатор ""%3"") еще не завершена.'"),
			ПредставлениеПрограммы, ДанныеКорреспондента.Наименование, ДанныеКорреспондента.Код);
			
		ВызватьИсключение СтрокаСообщенияОбОшибке;
	КонецЕсли;
	
	// ИНИЦИАЛИЗАЦИЯ ОБМЕНА ДАННЫМИ
	СтруктураНастроекОбмена = НастройкиОбменаДляУзлаИнформационнойБазы(
		ПараметрыОбмена.УзелИнформационнойБазы, ПараметрыОбмена.ДействиеПриОбмене, Неопределено, Ложь);
	Если ЗначениеЗаполнено(ПараметрыОбмена.ДатаНачалаОперации) Тогда
		СтруктураНастроекОбмена.ДатаНачала = ПараметрыОбмена.ДатаНачалаОперации;
	КонецЕсли;
	ЗафиксироватьНачалоОбменаВРегистреСведений(СтруктураНастроекОбмена);
	
	Если СтруктураНастроекОбмена.Отказ Тогда
		СтрокаСообщенияОбОшибке = НСтр("ru = 'Ошибка при инициализации процесса обмена данными.'");
		ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
		ВызватьИсключение СтрокаСообщенияОбОшибке;
	КонецЕсли;
	
	СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено;
	
	СтрокаСообщения = НСтр("ru = 'Начало процесса обмена данными для узла %1'", ОбщегоНазначения.КодОсновногоЯзыка());
	СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, СтруктураНастроекОбмена.УзелИнформационнойБазыНаименование);
	ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщения, СтруктураНастроекОбмена);
	
	Если СтруктураНастроекОбмена.ПроизводитьЗагрузкуДанных Тогда
		
		СозданВременныйФайл = Ложь;
		Если ПараметрыОбмена.ПолноеИмяФайлаСообщенияОбмена = ""
			И ПараметрыОбмена.СообщениеОбмена <> "" Тогда
			
			ПараметрыОбмена.ПолноеИмяФайлаСообщенияОбмена = ПолучитьИмяВременногоФайла(".xml");
			ТекстовыйФайл = Новый ТекстовыйДокумент;
			ТекстовыйФайл.УстановитьТекст(ПараметрыОбмена.СообщениеОбмена);
			ТекстовыйФайл.Записать(ПараметрыОбмена.ПолноеИмяФайлаСообщенияОбмена);
			СозданВременныйФайл = Истина;
		КонецЕсли;
		
		ПрочитатьСообщениеСИзменениямиДляУзла(СтруктураНастроекОбмена, ПараметрыОбмена.ПолноеИмяФайлаСообщенияОбмена, ПараметрыОбмена.СообщениеОбмена);
		
		// {Обработчик: ПослеЧтенияСообщенияОбмена} Начало
		СтандартнаяОбработка = Истина;
		
		ПослеЧтенияСообщенияОбмена(
					СтруктураНастроекОбмена.УзелИнформационнойБазы,
					ПараметрыОбмена.ПолноеИмяФайлаСообщенияОбмена,
					РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена),
					СтандартнаяОбработка);
		// {Обработчик: ПослеЧтенияСообщенияОбмена} Окончание
		
		Если СозданВременныйФайл Тогда
			
			Попытка
				УдалитьФайлы(ПараметрыОбмена.ПолноеИмяФайлаСообщенияОбмена);
			Исключение
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(),
					УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			КонецПопытки;
		КонецЕсли;
		
	ИначеЕсли СтруктураНастроекОбмена.ПроизводитьВыгрузкуДанных Тогда
		
		ЗаписатьСообщениеСИзменениямиДляУзла(СтруктураНастроекОбмена, ПараметрыОбмена.ПолноеИмяФайлаСообщенияОбмена, ПараметрыОбмена.СообщениеОбмена);
		
	КонецЕсли;
	
	ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
	
	Если Не РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена) Тогда
		ВызватьИсключение СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке;
	КонецЕсли;
	
КонецПроцедуры

// Записывает изменения узла информационной базы в файл во временном каталоге.
//
// Параметры:
//  СтруктураНастроекОбмена - Структура - структура со всеми необходимыми данными и объектами для выполнения обмена.
// 
Процедура ЗаписатьСообщениеСИзменениямиДляУзла(СтруктураНастроекОбмена, Знач ИмяФайлаСообщенияОбмена = "", СообщениеОбмена = "") Экспорт
	
	Если СтруктураНастроекОбмена.ЭтоОбменВРИБ Тогда // Обмен в РИБ
		
		Отказ = Ложь;
		СообщениеОбОшибке = "";
		
		// Получаем обработку обмена данными.
		ОбработкаОбменаДанными = СтруктураНастроекОбмена.ОбработкаОбменаДанными;
		
		// Устанавливаем имя файла сообщения обмена, который необходимо прочитать.
		ОбработкаОбменаДанными.УстановитьИмяФайлаСообщенияОбмена(ИмяФайлаСообщенияОбмена);
		
		ОбработкаОбменаДанными.ВыполнитьВыгрузкуДанных(Отказ, СообщениеОбОшибке);
		
		Если Отказ Тогда
			
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
			СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке = СообщениеОбОшибке;
			
		КонецЕсли;
		
	Иначе
		
		// {Обработчик: ПриВыгрузкеДанных} Начало. Переопределение стандартной обработки выгрузки данных.
		СтандартнаяОбработка         = Истина;
		КоличествоОбъектовОбработано = 0;
		
		Попытка
			
			ПараметрыВыполнения = Новый Структура;
			ПараметрыВыполнения.Вставить("УзелИнформационнойБазы",          СтруктураНастроекОбмена.УзелИнформационнойБазы);
			ПараметрыВыполнения.Вставить("КоличествоЭлементовВТранзакции",  СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции);
			ПараметрыВыполнения.Вставить("КлючСообщенияЖурналаРегистрации", СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации);
			ПараметрыВыполнения.Вставить("ИмяФайлаСообщенияОбмена",         ИмяФайлаСообщенияОбмена);
			
			Обработчики = Новый Массив;
			Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОбменСообщениями") Тогда
			    МодульОбменСообщениямиВнутренний = ОбщегоНазначения.ОбщийМодуль("ОбменСообщениямиВнутренний");
			    Обработчики.Добавить(МодульОбменСообщениямиВнутренний);
			КонецЕсли;
			Обработчики.Добавить(ОбменДаннымиПереопределяемый);
			
			ОбработчикПриВыгрузкеДанныхБСП(
				Обработчики,
			    ПараметрыВыполнения,
			    СтандартнаяОбработка,
			    СообщениеОбмена,
			    КоличествоОбъектовОбработано);
			
		Исключение
			
			СтрокаСообщенияОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			
			ЗаписьЖурналаРегистрации(СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
					СтруктураНастроекОбмена.УзелИнформационнойБазы.Метаданные(), 
					СтруктураНастроекОбмена.УзелИнформационнойБазы, СтрокаСообщенияОбОшибке);
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
			СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке = СтрокаСообщенияОбОшибке;
			Возврат;
		КонецПопытки;
		
		Если СтандартнаяОбработка = Ложь Тогда
			СтруктураНастроекОбмена.КоличествоОбъектовОбработано = КоличествоОбъектовОбработано;
			Возврат;
		КонецЕсли;
		// {Обработчик: ПриВыгрузкеДанных} Окончание
		
		// Универсальный обмен (обмен по правилам конвертации).
		Если СтруктураНастроекОбмена.ОбменПоПравиламКонвертацииОбъектов Тогда
			
			ФормироватьСообщениеОбмена = ПустаяСтрока(ИмяФайлаСообщенияОбмена);
			Если ФормироватьСообщениеОбмена Тогда
				ИмяФайлаСообщенияОбмена = ПолучитьИмяВременногоФайла(".xml");
			КонецЕсли;
			
			// Получаем инициализированную обработку обмена данными.
			ОбработкаОбменаДаннымиXML = СтруктураНастроекОбмена.ОбработкаОбменаДанными; //ОбработкаОбъект.КонвертацияОбъектовXDTO
			ОбработкаОбменаДаннымиXML.ИмяФайлаОбмена = ИмяФайлаСообщенияОбмена;
			
			// выгрузка данных
			Попытка
				ОбработкаОбменаДаннымиXML.ВыполнитьВыгрузкуДанных();
			Исключение
				СтрокаСообщенияОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			
				ЗаписьЖурналаРегистрации(СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
						СтруктураНастроекОбмена.УзелИнформационнойБазы.Метаданные(), 
						СтруктураНастроекОбмена.УзелИнформационнойБазы, СтрокаСообщенияОбОшибке);
				СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
				СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке = СтрокаСообщенияОбОшибке;
				Возврат;
			КонецПопытки;
			
			Если ФормироватьСообщениеОбмена Тогда
				ТекстовыйФайл = Новый ТекстовыйДокумент;
				ТекстовыйФайл.Прочитать(ИмяФайлаСообщенияОбмена, КодировкаТекста.UTF8);
				СообщениеОбмена = ТекстовыйФайл.ПолучитьТекст();
				УдалитьФайлы(ИмяФайлаСообщенияОбмена);
			КонецЕсли;
			
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = ОбработкаОбменаДаннымиXML.РезультатВыполненияОбмена();
			
			// Фиксируем состояние выполнения обмена данными.
			СтруктураНастроекОбмена.КоличествоОбъектовОбработано = ОбработкаОбменаДаннымиXML.СчетчикВыгруженныхОбъектов();
			СтруктураНастроекОбмена.СообщениеПриОбмене           = ОбработкаОбменаДаннымиXML.КомментарийПриВыгрузкеДанных;
			СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке      = ОбработкаОбменаДаннымиXML.СтрокаСообщенияОбОшибке();
			
		Иначе // Стандартный обмен (платформенная сериализация).
			
			Отказ = Ложь;
			КоличествоОбъектовОбработано = 0;
			
			Попытка
				ВыполнитьСтандартнуюВыгрузкуИзмененийДляУзла(Отказ,
									СтруктураНастроекОбмена.УзелИнформационнойБазы,
									ИмяФайлаСообщенияОбмена,
									СообщениеОбмена,
									СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции,
									СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации,
									КоличествоОбъектовОбработано);
			Исключение
				СтрокаСообщенияОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			
				ЗаписьЖурналаРегистрации(СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
						СтруктураНастроекОбмена.УзелИнформационнойБазы.Метаданные(), 
						СтруктураНастроекОбмена.УзелИнформационнойБазы, СтрокаСообщенияОбОшибке);
				СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке = СтрокаСообщенияОбОшибке;
				Отказ = Истина;
			КонецПопытки;
			
			СтруктураНастроекОбмена.КоличествоОбъектовОбработано = КоличествоОбъектовОбработано;
			
			Если Отказ Тогда
				
				СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Получает сообщение обмена с новыми данными и загружает данные в информационную базу.
//
// Параметры:
//  СтруктураНастроекОбмена - Структура - структура со всеми необходимыми данными и объектами для выполнения обмена.
// 
Процедура ПрочитатьСообщениеСИзменениямиДляУзла(СтруктураНастроекОбмена,
		Знач ИмяФайлаСообщенияОбмена = "", СообщениеОбмена = "", Знач ТолькоПараметры = Ложь) Экспорт
	
	Если СтруктураНастроекОбмена.ЭтоОбменВРИБ Тогда // Обмен в РИБ
		
		Отказ = Ложь;
		
		// Получаем обработку обмена данными.
		ОбработкаОбменаДанными = СтруктураНастроекОбмена.ОбработкаОбменаДанными; //ОбработкаОбъект.КонвертацияОбъектовРаспределенныхИнформационныхБаз
		
		// Устанавливаем имя файла сообщения обмена, который необходимо прочитать.
		ОбработкаОбменаДанными.УстановитьИмяФайлаСообщенияОбмена(ИмяФайлаСообщенияОбмена);
		
		СообщениеОбОшибке = "";
		ОбработкаОбменаДанными.ВыполнитьЗагрузкуДанных(Отказ, ТолькоПараметры, СообщениеОбОшибке);
		
		Если Отказ Тогда
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
			СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке   = СообщениеОбОшибке;
		КонецЕсли;
		
	Иначе
		
		// {Обработчик: ПриЗагрузкеДанных} Начало. Переопределение стандартной обработки загрузки данных.
		СтандартнаяОбработка         = Истина;
		КоличествоОбъектовОбработано = 0;
		
		Попытка
			
			ПараметрыВыполнения = Новый Структура;
			ПараметрыВыполнения.Вставить("УзелИнформационнойБазы",          СтруктураНастроекОбмена.УзелИнформационнойБазы);
			ПараметрыВыполнения.Вставить("КоличествоЭлементовВТранзакции",  СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции);
			ПараметрыВыполнения.Вставить("КлючСообщенияЖурналаРегистрации", СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации);
			ПараметрыВыполнения.Вставить("ИмяФайлаСообщенияОбмена",         ИмяФайлаСообщенияОбмена);
			
			Обработчики = Новый Массив;
			Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОбменСообщениями") Тогда
				МодульОбменСообщениямиВнутренний = ОбщегоНазначения.ОбщийМодуль("ОбменСообщениямиВнутренний");
				Обработчики.Добавить(МодульОбменСообщениямиВнутренний);
			КонецЕсли;
			Обработчики.Добавить(ОбменДаннымиПереопределяемый);
			
			ОбработчикПриЗагрузкеДанныхБСП(
				Обработчики,
				ПараметрыВыполнения,
				СтандартнаяОбработка,
				СообщениеОбмена,
				КоличествоОбъектовОбработано);
			
		Исключение
			СтрокаСообщенияОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			
			ЗаписьЖурналаРегистрации(СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
					СтруктураНастроекОбмена.УзелИнформационнойБазы.Метаданные(), 
					СтруктураНастроекОбмена.УзелИнформационнойБазы, СтрокаСообщенияОбОшибке);
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
			СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке = СтрокаСообщенияОбОшибке;
			Возврат;
		КонецПопытки;
		
		Если СтандартнаяОбработка = Ложь Тогда
			СтруктураНастроекОбмена.КоличествоОбъектовОбработано = КоличествоОбъектовОбработано;
			Возврат;
		КонецЕсли;
		// {Обработчик: ПриЗагрузкеДанных} Окончание
		
		// Универсальный обмен (обмен по правилам конвертации).
		Если СтруктураНастроекОбмена.ОбменПоПравиламКонвертацииОбъектов Тогда
			
			// Получаем инициализированную обработку обмена данными.
			ОбработкаОбменаДаннымиXML = СтруктураНастроекОбмена.ОбработкаОбменаДанными; //ОбработкаОбъект.КонвертацияОбъектовXDTO
			ОбработкаОбменаДаннымиXML.ИмяФайлаОбмена = ИмяФайлаСообщенияОбмена;
			
			// загрузка данных
			Если ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(СтруктураНастроекОбмена.ИмяПланаОбмена) Тогда
				ПараметрыЗагрузки = Новый Структура;
				ПараметрыЗагрузки.Вставить("ОбменДаннымиСВнешнейСистемой",
					СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.ВнешняяСистема);
				
				ОбработкаОбменаДаннымиXML.ВыполнитьЗагрузкуДанных(ПараметрыЗагрузки);
				
				ПолученыДанныеДляСопоставления = Ложь;
				Если Не ОбработкаОбменаДаннымиXML.КомпонентыОбмена.ФлагОшибки Тогда
					ПолученыДанныеДляСопоставления = (ОбработкаОбменаДаннымиXML.КомпонентыОбмена.НомерВходящегоСообщения > 0
						И ОбработкаОбменаДаннымиXML.КомпонентыОбмена.НомерСообщенияПолученногоКорреспондентом = 0);
				КонецЕсли;
				СтруктураНастроекОбмена.ДополнительныеПараметры.Вставить("ПолученыДанныеДляСопоставления", ПолученыДанныеДляСопоставления);
			Иначе
				ОбработкаОбменаДаннымиXML.ВыполнитьЗагрузкуДанных();
			КонецЕсли;
			
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = ОбработкаОбменаДаннымиXML.РезультатВыполненияОбмена();
			
			// Фиксируем состояние выполнения обмена данными.
			СтруктураНастроекОбмена.КоличествоОбъектовОбработано = ОбработкаОбменаДаннымиXML.СчетчикЗагруженныхОбъектов();
			СтруктураНастроекОбмена.СообщениеПриОбмене           = ОбработкаОбменаДаннымиXML.КомментарийПриЗагрузкеДанных;
			СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке      = ОбработкаОбменаДаннымиXML.СтрокаСообщенияОбОшибке();
			
		Иначе // Стандартный обмен (платформенная сериализация).
			
			КоличествоОбъектовОбработано = 0;
			РезультатВыполненияОбмена = Неопределено;
			
			ВыполнитьСтандартнуюЗагрузкуИзмененийДляУзла(
				СтруктураНастроекОбмена.УзелИнформационнойБазы,
				ИмяФайлаСообщенияОбмена,
				СообщениеОбмена,
				СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции,
				СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации,
				КоличествоОбъектовОбработано,
				РезультатВыполненияОбмена);
			
			СтруктураНастроекОбмена.КоличествоОбъектовОбработано = КоличествоОбъектовОбработано;
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = РезультатВыполненияОбмена;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ИнтерактивноеИзменениеВыгрузки

// Сохраняет настройки с указанным именем по данным ДополнениеВыгрузки.
//
// Параметры:
//     ДополнениеВыгрузки     - Структура
//                            - РеквизитФормыКоллекция - описание параметров выгрузки.
//     ПредставлениеНастройки - Строка                            - название сохраняемой настройки.
//
Процедура ИнтерактивноеИзменениеВыгрузкиСохранитьНастройки(ДополнениеВыгрузки, Знач ПредставлениеНастройки) Экспорт
	
	ОбработкаДополнения = Обработки.ИнтерактивноеИзменениеВыгрузки.Создать();
	ЗаполнитьЗначенияСвойств(ОбработкаДополнения, ДополнениеВыгрузки, ,
		"ДополнительнаяРегистрация, ДополнительнаяРегистрацияСценарияУзла");
	
	ЗаполнитьТаблицуЗначений(ОбработкаДополнения.ДополнительнаяРегистрация,             ДополнениеВыгрузки.ДополнительнаяРегистрация);
	ЗаполнитьТаблицуЗначений(ОбработкаДополнения.ДополнительнаяРегистрацияСценарияУзла, ДополнениеВыгрузки.ДополнительнаяРегистрацияСценарияУзла);
	
	// Компоновщик настроек собираем заново.
	Данные = ОбработкаДополнения.КомпоновщикНастроекОбщегоОтбора();
	
	Если ПустаяСтрока(ДополнениеВыгрузки.АдресКомпоновщикаВсехДокументов) Тогда
		ИсточникНастроек = ДополнениеВыгрузки.КомпоновщикОтбораВсехДокументов.Настройки;
	Иначе
		СтруктураКомпоновщика = ПолучитьИзВременногоХранилища(ДополнениеВыгрузки.АдресКомпоновщикаВсехДокументов);
		ИсточникНастроек = СтруктураКомпоновщика.Настройки;
	КонецЕсли;
		
	ОбработкаДополнения.КомпоновщикОтбораВсехДокументов = Новый КомпоновщикНастроекКомпоновкиДанных;
	ОбработкаДополнения.КомпоновщикОтбораВсехДокументов.Инициализировать( Новый ИсточникДоступныхНастроекКомпоновкиДанных(Данные.СхемаКомпоновки) );
	ОбработкаДополнения.КомпоновщикОтбораВсехДокументов.ЗагрузитьНастройки(ИсточникНастроек);
	
	// Собственно сохранение
	ОбработкаДополнения.СохранитьТекущееВНастройки(ПредставлениеНастройки);
	
	// Текущее представление запомненных настроек.
	ДополнениеВыгрузки.ПредставлениеТекущейНастройки = ПредставлениеНастройки;
	
КонецПроцедуры

// Имя для сохранения и восстановления настроек при интерактивном дополнении выгрузки.
//
Функция ДополнениеВыгрузкиИмяАвтоСохраненияНастроек() Экспорт
	Возврат НСтр("ru = 'Последняя отправка (сохраняется автоматически)'");
КонецФункции

// Производит дополнительную регистрацию объектов по настройкам.
//
// Параметры:
//     ДополнениеВыгрузки     - Структура
//                            - ДанныеФормыКоллекция - описание параметров выгрузки.
//
Процедура ИнтерактивноеИзменениеВыгрузкиЗарегистрироватьДополнительныеДанные(Знач ДополнениеВыгрузки) Экспорт
	
	Если ДополнениеВыгрузки.ВариантВыгрузки <= 0 Тогда
		Возврат;
	КонецЕсли;
	
	ОбъектОтчета = Обработки.ИнтерактивноеИзменениеВыгрузки.Создать();
	ЗаполнитьЗначенияСвойств(ОбъектОтчета, ДополнениеВыгрузки,,"ДополнительнаяРегистрация, ДополнительнаяРегистрацияСценарияУзла");
		
	Если ОбъектОтчета.ВариантВыгрузки=1 Тогда
		// За период с отбором, дополнительная пустая.
		
	ИначеЕсли ДополнениеВыгрузки.ВариантВыгрузки=2 Тогда
		// Детально настроено
		ОбъектОтчета.КомпоновщикОтбораВсехДокументов = Неопределено;
		ОбъектОтчета.ПериодОтбораВсехДокументов      = Неопределено;
		
		ЗаполнитьТаблицуЗначений(ОбъектОтчета.ДополнительнаяРегистрация, ДополнениеВыгрузки.ДополнительнаяРегистрация);
		
	ИначеЕсли ДополнениеВыгрузки.ВариантВыгрузки=3 Тогда
		// По сценарию узла, имитируем детальное.
		ОбъектОтчета.ВариантВыгрузки = 2;
		
		ОбъектОтчета.КомпоновщикОтбораВсехДокументов = Неопределено;
		ОбъектОтчета.ПериодОтбораВсехДокументов      = Неопределено;
		
		ЗаполнитьТаблицуЗначений(ОбъектОтчета.ДополнительнаяРегистрация, ДополнениеВыгрузки.ДополнительнаяРегистрацияСценарияУзла);
	КонецЕсли;
	
	ОбъектОтчета.ЗарегистрироватьДополнительныеИзменения();
КонецПроцедуры

#КонецОбласти

#Область ОбщегоНазначения

// Регистрирует что обмен был произведен и фиксирует информацию в протоколе.
//
// Параметры:
//  СтруктураНастроекОбмена - Структура - структура со всеми необходимыми данными и объектами для выполнения обмена.
// 
Процедура ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена) Экспорт
	
	// Статус "Неопределено" в конце обмена свидетельствует об успешном выполнении обмена.
	Если СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено Тогда
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Выполнено;
	КонецЕсли;
	
	// Формируем итоговое сообщение для протокола.
	Если СтруктураНастроекОбмена.ЭтоОбменВРИБ Тогда
		СтрокаСообщения = НСтр("ru = '%1, %2'", ОбщегоНазначения.КодОсновногоЯзыка());
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
							СтруктураНастроекОбмена.РезультатВыполненияОбмена,
							СтруктураНастроекОбмена.ДействиеПриОбмене);
	Иначе
		СтрокаСообщения = НСтр("ru = '%1, %2; Объектов обработано: %3'", ОбщегоНазначения.КодОсновногоЯзыка());
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
							СтруктураНастроекОбмена.РезультатВыполненияОбмена,
							СтруктураНастроекОбмена.ДействиеПриОбмене,
							СтруктураНастроекОбмена.КоличествоОбъектовОбработано);
	КонецЕсли;
	
	СтруктураНастроекОбмена.ДатаОкончания = ТекущаяДатаСеанса();
	
	УстановитьПривилегированныйРежим(Истина);
	
	// Фиксируем состояние обмена в РС.
	ЗафиксироватьЗавершениеОбменаВРегистреСведений(СтруктураНастроекОбмена);
	
	// Если обмен данными был успешно выполнен.
	Если РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена) Тогда
		
		ЗафиксироватьУспешныйОбменДаннымиВРегистреСведений(СтруктураНастроекОбмена);
		
		РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.СнятьПризнакОтправкиДанных(СтруктураНастроекОбмена.УзелИнформационнойБазы);
		
	КонецЕсли;
	
	ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщения, СтруктураНастроекОбмена);
	
КонецПроцедуры

Процедура ЗафиксироватьНачалоОбменаВРегистреСведений(СтруктураНастроекОбмена) Экспорт
	
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("УзелИнформационнойБазы",    СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураЗаписи.Вставить("ДействиеПриОбмене",         СтруктураНастроекОбмена.ДействиеПриОбмене);
	
	СтруктураЗаписи.Вставить("ДатаНачала",                СтруктураНастроекОбмена.ДатаНачала);
	
	РегистрыСведений.СостоянияОбменовДанными.ОбновитьЗапись(СтруктураЗаписи);
	
КонецПроцедуры

// Создает запись в журнале регистрации о событии обмена данными/транспорте сообщений обмена.
//
Процедура ЗаписьЖурналаРегистрацииОбменаДанными(Комментарий, СтруктураНастроекОбмена, ЭтоОшибка = Ложь) Экспорт
	
	Уровень = ?(ЭтоОшибка, УровеньЖурналаРегистрации.Ошибка, УровеньЖурналаРегистрации.Информация);
	
	Если СтруктураНастроекОбмена.Свойство("УзелИнформационнойБазы") Тогда
		
		ЗаписьЖурналаРегистрации(СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации, 
			Уровень,
			СтруктураНастроекОбмена.УзелИнформационнойБазы.Метаданные(),
			СтруктураНастроекОбмена.УзелИнформационнойБазы,
			Комментарий);
			
	Иначе
		ЗаписьЖурналаРегистрации(СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации, Уровень,,, Комментарий);
	КонецЕсли;
	
КонецПроцедуры

// Возвращает признак успешного выполнения обмена данными.
//
Функция РезультатВыполненияОбменаВыполнено(РезультатВыполненияОбмена) Экспорт
	
	Возврат РезультатВыполненияОбмена = Неопределено
		ИЛИ РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Выполнено
		ИЛИ РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями;
	
КонецФункции

Функция УникальноеИмяФайлаСообщенияОбмена(Расширение = "xml") Экспорт
	
	Результат = "Message{GUID}." + Расширение;
	
	Результат = СтрЗаменить(Результат, "GUID", Строка(Новый УникальныйИдентификатор));
	
	Возврат Результат;
КонецФункции

Функция НайтиИмяПланаОбменаЧерезУниверсальныйФормат(Знач ИсходноеИмяПланаОбмена) Экспорт
	
	ИмяПланаОбмена = ОбменДаннымиТрансляцияФорматаПовтИсп.ТранслироватьИмя(ИсходноеИмяПланаОбмена, "en");
	
	Если Метаданные.ПланыОбмена.Найти(ИмяПланаОбмена) <> Неопределено Тогда
		Возврат ИмяПланаОбмена;
	КонецЕсли;

	Для Каждого ПланОбмена Из ОбменДаннымиПовтИсп.ПланыОбменаБСП() Цикл
		
		Если ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(ПланОбмена)
			И ОбменДаннымиПовтИсп.ЭтоГлобальныйОбменЧерезУниверсальныйФормат(ПланОбмена) Тогда
				
			Возврат ПланОбмена;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#Область ОбщиеМетодыМеханизмовКонвертацииДанных

Функция МодульПомощникНастройкиСинхронизацииДанныхМеждуПриложениямиВИнтернете() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		Возврат ОбщегоНазначения.ОбщийМодуль("Обработки.ПомощникНастройкиСинхронизацииДанныхМеждуПриложениямиВИнтернете");
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

Функция МодульПомощникИнтерактивногоОбменаДаннымиВМоделиСервиса() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		Возврат ОбщегоНазначения.ОбщийМодуль("Обработки.ПомощникИнтерактивногоОбменаДаннымиВМоделиСервиса");
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

Функция МодульПомощникСозданияОбменаДанными() Экспорт
	
	Возврат ОбщегоНазначения.ОбщийМодуль("Обработки.ПомощникСозданияОбменаДанными");
	
КонецФункции

Функция МодульПомощникИнтерактивногоОбменаДанными() Экспорт
	
	Возврат ОбщегоНазначения.ОбщийМодуль("Обработки.ПомощникИнтерактивногоОбменаДанными");
	
КонецФункции

Функция ПредопределенныеУзлыПлановОбменаБСП()
	
	Результат = Новый Массив;
	
	Для Каждого ИмяПланаОбмена Из ОбменДаннымиПовтИсп.ПланыОбменаБСП() Цикл
		Результат.Добавить(ПланыОбмена[ИмяПланаОбмена].ЭтотУзел());
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПроверкаДатЗапретаОтключена()
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДатыЗапретаИзменения") Тогда
		МодульДатыЗапретаИзменения = ОбщегоНазначения.ОбщийМодуль("ДатыЗапретаИзменения");
		Возврат МодульДатыЗапретаИзменения.ПроверкаДатЗапретаОтключена();
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция НовыйУзелОбменаДаннымиXDTO(
		ИмяПланаОбмена,
		ИдентификаторНастройки,
		ИдентификаторКорреспондента,
		НаименованиеКорреспондента,
		ВерсияФорматаОбмена)
	
	МенеджерПланаОбмена = ПланыОбмена[ИмяПланаОбмена];
	
	НовыйУзел = МенеджерПланаОбмена.СоздатьУзел();
	НовыйУзел.Код          = ИдентификаторКорреспондента;
	НовыйУзел.Наименование = НаименованиеКорреспондента;
	
	Если ОбщегоНазначения.ЕстьРеквизитОбъекта("ВариантНастройки", Метаданные.ПланыОбмена[ИмяПланаОбмена]) Тогда
		НовыйУзел.ВариантНастройки = ИдентификаторНастройки;
	КонецЕсли;
	
	НовыйУзел.ВерсияФорматаОбмена = ВерсияФорматаОбмена;
	
	НовыйУзел.Заполнить(Неопределено);
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных()
		И ЭтоРазделенныйПланОбменаБСП(ИмяПланаОбмена) Тогда
		
		НовыйУзел.РегистрироватьИзменения = Истина;
		
	КонецЕсли;
	
	НовыйУзел.ОбменДанными.Загрузка = Истина;
	НовыйУзел.Записать();
	
	Возврат НовыйУзел.Ссылка;
	
КонецФункции

Функция КоличествоЭлементовВТранзакцииВыполняемогоДействия(Действие)
	
	Если Действие = Перечисления.ДействияПриОбмене.ВыгрузкаДанных Тогда
		КоличествоЭлементов = КоличествоЭлементовВТранзакцииВыгрузкиДанных();
	Иначе
		КоличествоЭлементов = КоличествоЭлементовВТранзакцииЗагрузкиДанных();
	КонецЕсли;
	
	Возврат КоличествоЭлементов;
	
КонецФункции

Процедура ОтключитьПроверкуДатЗапрета(Отключить = Истина)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДатыЗапретаИзменения") Тогда
		МодульДатыЗапретаИзменения = ОбщегоНазначения.ОбщийМодуль("ДатыЗапретаИзменения");
		МодульДатыЗапретаИзменения.ОтключитьПроверкуДатЗапрета(Отключить);
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьОбновлениеНастроекОбмена(УзелИнформационнойБазы)
	
	Если ОбменДаннымиПовтИсп.ЭтоУзелОбменаСообщениями(УзелИнформационнойБазы) Тогда
		Возврат;
	КонецЕсли;
	
	НаборУдалитьНастройкиТранспортаОбмена = РегистрыСведений.УдалитьНастройкиТранспортаОбмена.СоздатьНаборЗаписей();
	НаборУдалитьНастройкиТранспортаОбмена.Отбор.УзелИнформационнойБазы.Установить(УзелИнформационнойБазы);
	НаборУдалитьНастройкиТранспортаОбмена.Прочитать();
	
	СостояниеОбработки = ОбновлениеИнформационнойБазы.ОбъектОбработан(НаборУдалитьНастройкиТранспортаОбмена);
	Если Не СостояниеОбработки.Обработан Тогда
		РегистрыСведений.НастройкиТранспортаОбменаДанными.ПеренестиНастройкиТранспортаОбменаДаннымиКорреспондента(УзелИнформационнойБазы);
	КонецЕсли;
	
	НаборОбщиеНастройкиУзловИнформационныхБаз = РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.СоздатьНаборЗаписей();
	НаборОбщиеНастройкиУзловИнформационныхБаз.Отбор.УзелИнформационнойБазы.Установить(УзелИнформационнойБазы);
	НаборОбщиеНастройкиУзловИнформационныхБаз.Прочитать();
	
	Если НаборОбщиеНастройкиУзловИнформационныхБаз.Количество() = 0 Тогда
		РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ОбновитьОбщиеНастройкиКорреспондента(УзелИнформационнойБазы);
	Иначе
		СостояниеОбработки = ОбновлениеИнформационнойБазы.ОбъектОбработан(НаборОбщиеНастройкиУзловИнформационныхБаз);
		Если Не СостояниеОбработки.Обработан Тогда
			РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ОбновитьОбщиеНастройкиКорреспондента(УзелИнформационнойБазы);
		КонецЕсли;
	КонецЕсли;
	
	Если ЭтоПланОбменаXDTO(УзелИнформационнойБазы) Тогда
		НаборНастройкиОбменаДаннымиXDTO = РегистрыСведений.НастройкиОбменаДаннымиXDTO.СоздатьНаборЗаписей();
		НаборНастройкиОбменаДаннымиXDTO.Отбор.УзелИнформационнойБазы.Установить(УзелИнформационнойБазы);
		НаборНастройкиОбменаДаннымиXDTO.Прочитать();
		
		Если НаборНастройкиОбменаДаннымиXDTO.Количество() = 0 Тогда
			РегистрыСведений.НастройкиОбменаДаннымиXDTO.ОбновитьНастройкиОбменаДаннымиXDTOКорреспондента(УзелИнформационнойБазы);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьОтложенноеПроведениеДокументов(
		ДокументыДляОтложенногоПроведения,
		УзелКорреспондента,
		ДополнительныеСвойстваДляОтложенногоПроведения = Неопределено,
		КомпонентыОбмена = Неопределено) Экспорт
	
	Если ДокументыДляОтложенногоПроведения.Количество() = 0 Тогда
		Возврат; // нет документов в очереди
	КонецЕсли;
	
	// Сворачиваем таблицу по уникальным полям.
	ДокументыДляОтложенногоПроведения.Свернуть("ДокументСсылка, ДатаДокумента");
	
	// Сортируем документы по возрастанию даты документов.
	ОбъектСравнения = Новый СравнениеЗначений;
	ДокументыДляОтложенногоПроведения.Сортировать("ДатаДокумента, ДокументСсылка", ОбъектСравнения);
	
	ПроверкаДатЗапретаОтключена = ПроверкаДатЗапретаОтключена();
	ОтключитьПроверкуДатЗапрета(Истина);
	Попытка
		Для Каждого СтрокаТаблицы Из ДокументыДляОтложенногоПроведения Цикл
			
			ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
			
			Если СтрокаТаблицы.ДокументСсылка.Пустая() Тогда
				Продолжить;
			КонецЕсли;
			
			Если Не ОбщегоНазначения.СсылкаСуществует(СтрокаТаблицы.ДокументСсылка) Тогда
				Продолжить;
			КонецЕсли;
			
			ДополнительныеСвойстваОбъекта = Неопределено;
			Если ДополнительныеСвойстваДляОтложенногоПроведения <> Неопределено Тогда
				ДополнительныеСвойстваОбъекта = ДополнительныеСвойстваДляОтложенногоПроведения.Получить(СтрокаТаблицы.ДокументСсылка);
			КонецЕсли;
			
			ВыполнитьПроведениеДокументаПриЗагрузке(
				УзелКорреспондента,
				СтрокаТаблицы.ДокументСсылка,
				Истина,
				ДополнительныеСвойстваОбъекта);
				
			Если КомпонентыОбмена <> Неопределено Тогда
				Событие = "ОтложенноеПроведениеДокументов." + СтрокаТаблицы.ДокументСсылка.Метаданные().ПолноеИмя();
				ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
					ВремяНачала, Событие, СтрокаТаблицы.ДокументСсылка, КомпонентыОбмена,
					ОбменДаннымиОценкаПроизводительности.ТипСобытияПрикладное());
			КонецЕсли;
			
		КонецЦикла;
	Исключение
		ОтключитьПроверкуДатЗапрета(ПроверкаДатЗапретаОтключена);
		ВызватьИсключение;
	КонецПопытки;
	ОтключитьПроверкуДатЗапрета(ПроверкаДатЗапретаОтключена);
	
КонецПроцедуры

Процедура ВыполнитьПроведениеДокументаПриЗагрузке(
		УзелКорреспондента,
		ДокументСсылка,
		РегистрироватьПроблемыВРезультатахОбмена,
		ДополнительныеСвойстваОбъекта = Неопределено) Экспорт
	
	ОписаниеОшибки          = "";
	ДокументПроведенУспешно = Ложь;
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных;
	    ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(ДокументСсылка));
	    ЭлементБлокировки.УстановитьЗначение("Ссылка", ДокументСсылка);
	    Блокировка.Заблокировать();
		
		Объект = ДокументСсылка.ПолучитьОбъект();
		
		// Устанавливаем узел-отправитель для предотвращения регистрации объекта на узле, для которого производим загрузку
		// проведение выполняем не в режиме загрузки.
		УстановитьОбменДаннымиЗагрузка(Объект, Ложь, Ложь, УзелКорреспондента);
		
		Если ДополнительныеСвойстваОбъекта <> Неопределено Тогда
			Для Каждого Свойство Из ДополнительныеСвойстваОбъекта Цикл
				Объект.ДополнительныеСвойства.Вставить(Свойство.Ключ, Свойство.Значение);
			КонецЦикла;
		КонецЕсли;
		
		Объект.ДополнительныеСвойства.Вставить("ОтложенноеПроведение");
		
		Если Объект.ПроверитьЗаполнение() Тогда
			
			// При проведении документа снимаем запрет на выполнение ПРО,
			// т.к. ПРО были проигнорированы при обычной записи документа с целью оптимизации скорости загрузки данных.
			Если Объект.ДополнительныеСвойства.Свойство("ОтключитьМеханизмРегистрацииОбъектов") Тогда
				Объект.ДополнительныеСвойства.Удалить("ОтключитьМеханизмРегистрацииОбъектов");
			КонецЕсли;
			
			Объект.ДополнительныеСвойства.Вставить("ПропуститьПроверкуЗапретаИзменения");
			
			// Выполняем попытку проведения документа.
			Объект.Записать(РежимЗаписиДокумента.Проведение);
			
			ДокументПроведенУспешно = Объект.Проведен;
			
		КонецЕсли;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		
		ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		ДокументПроведенУспешно = Ложь;
		
	КонецПопытки;
	
	Если Не ДокументПроведенУспешно Тогда
		
		ЗарегистрироватьОшибкуПроведенияДокумента(
			Объект, УзелКорреспондента, ОписаниеОшибки, РегистрироватьПроблемыВРезультатахОбмена);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьОтложеннуюЗаписьОбъектов(ОбъектыДляОтложеннойЗаписи, УзелКорреспондента, КомпонентыОбмена = Неопределено) Экспорт
	
	Если ОбъектыДляОтложеннойЗаписи.Количество() = 0 Тогда
		Возврат; // Нет объектов в очереди
	КонецЕсли;
	
	ПроверкаДатЗапретаОтключена = ПроверкаДатЗапретаОтключена();
	ОтключитьПроверкуДатЗапрета(Истина);
	Попытка
		Для Каждого ОбъектСоответствия Из ОбъектыДляОтложеннойЗаписи Цикл
			
			ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
			
			Если ОбъектСоответствия.Ключ.Пустая() Тогда
				Продолжить;
			КонецЕсли;
			
			Если Не ОбщегоНазначения.СсылкаСуществует(ОбъектСоответствия.Ключ) Тогда
				Продолжить;
			КонецЕсли;
			
			ОписаниеОшибки       = "";
			ОбъектЗаписанУспешно = Ложь;
			
			НачатьТранзакцию();
			Попытка
				Блокировка = Новый БлокировкаДанных;
				ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(ОбъектСоответствия.Ключ));
				ЭлементБлокировки.УстановитьЗначение("Ссылка", ОбъектСоответствия.Ключ);
				Блокировка.Заблокировать();
				
				Объект = ОбъектСоответствия.Ключ.ПолучитьОбъект();
			
				// Устанавливаем узел-отправитель для предотвращения регистрации объекта на узле, для которого производим загрузку
				// проведение выполняем не в режиме загрузки.
				УстановитьОбменДаннымиЗагрузка(Объект, Ложь, Ложь, УзелКорреспондента);
				
				ДополнительныеСвойства = ОбъектСоответствия.Значение;
				
				Для Каждого Свойство Из ДополнительныеСвойства Цикл
					
					Объект.ДополнительныеСвойства.Вставить(Свойство.Ключ, Свойство.Значение);
					
				КонецЦикла;
				
				Объект.ДополнительныеСвойства.Вставить("ОтложеннаяЗапись");
				
				Если Объект.ПроверитьЗаполнение() Тогда
					
					// При проведении документа снимаем запрет на выполнение ПРО,
					// т.к. ПРО были проигнорированы при обычной записи с целью оптимизации скорости загрузки данных.
					Если Объект.ДополнительныеСвойства.Свойство("ОтключитьМеханизмРегистрацииОбъектов") Тогда
						Объект.ДополнительныеСвойства.Удалить("ОтключитьМеханизмРегистрацииОбъектов");
					КонецЕсли;
					
					Объект.ДополнительныеСвойства.Вставить("ПропуститьПроверкуЗапретаИзменения");
					
					// Выполняем попытку записи объекта.
					СведенияОВерсииОбъекта = Неопределено;
					Если Объект.ДополнительныеСвойства.Свойство("СведенияОВерсииОбъекта", СведенияОВерсииОбъекта) Тогда
						ОбменДаннымиСобытия.ПриСозданииВерсииОбъекта(Объект, СведенияОВерсииОбъекта, Истина, УзелКорреспондента);
					КонецЕсли;
					Объект.Записать();
					
					ОбъектЗаписанУспешно = Истина;
					
				Иначе
					
					ОбъектЗаписанУспешно = Ложь;
					
					ОписаниеОшибки = НСтр("ru = 'Ошибка проверки заполнения реквизитов'");
					
				КонецЕсли;
				
				ЗафиксироватьТранзакцию();
				
			Исключение
				
				ОтменитьТранзакцию();
				
				ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
				
				ОбъектЗаписанУспешно = Ложь;
				
			КонецПопытки;
			
			Если Не ОбъектЗаписанУспешно Тогда
				
				ЗарегистрироватьОшибкуЗаписиОбъекта(Объект, УзелКорреспондента, ОписаниеОшибки);
				
			КонецЕсли;
			
			Если КомпонентыОбмена <> Неопределено Тогда
				Событие = "ВыполнитьОтложеннуюЗаписьОбъектов." + Объект.Метаданные().ПолноеИмя();
				ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
					ВремяНачала, Событие, Объект, КомпонентыОбмена,
					ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
			КонецЕсли;
			
		КонецЦикла;
	Исключение
		ОтключитьПроверкуДатЗапрета(ПроверкаДатЗапретаОтключена);
		ВызватьИсключение;
	КонецПопытки;
	ОтключитьПроверкуДатЗапрета(ПроверкаДатЗапретаОтключена);
	
КонецПроцедуры

Процедура ЗаблокироватьУзелОбмена(УзелОбмена, Отказ) Экспорт
	
	Попытка
		
		ЗаблокироватьДанныеДляРедактирования(УзелОбмена);
		
	Исключение
		
		Отказ = Истина;
		
		ШаблонСообщения = НСтр("ru = 'Не удалось заблокировать узел плана обмена [%1].
			|Вероятно, обмен данными уже выполняется. Повторите попытку позже.'", ОбщегоНазначения.КодОсновногоЯзыка());
		
		СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, УзелОбмена);
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Ошибка,
			УзелОбмена.Метаданные(), УзелОбмена, СообщениеОбОшибке);
			
		ВызватьИсключение СообщениеОбОшибке;
		
	КонецПопытки;
	
КонецПроцедуры

Процедура ПередВыполнениемОбменов(УзелИнформационнойБазы, Отказ)
	
	ПроверитьВозможностьВыполненияОбменов();
	
	ПроверитьИспользованиеОбменаДанными();
	
КонецПроцедуры

Процедура ПослеВыполненияОбменов(УзелИнформационнойБазы, Отказ)
	
	РазблокироватьУзелОбмена(УзелИнформационнойБазы, Отказ);
	
КонецПроцедуры

Процедура РазблокироватьУзелОбмена(УзелОбмена, Отказ) Экспорт
	
	Попытка
		
		РазблокироватьДанныеДляРедактирования(УзелОбмена);
		
	Исключение
		
		Отказ = Истина;
		
		ШаблонСообщения = НСтр("ru = 'Не удалось разблокировать узел плана обмена [%1].
			|Вероятно, обмен данными уже выполняется. Повторите попытку позже.'", ОбщегоНазначения.КодОсновногоЯзыка());
		
		СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, УзелОбмена);
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Ошибка,
			УзелОбмена.Метаданные(), УзелОбмена, СообщениеОбОшибке);
			
		ВызватьИсключение СообщениеОбОшибке;
		
	КонецПопытки;
	
КонецПроцедуры

#КонецОбласти

#Область ОбновлениеИнформационнойБазы

Процедура УстановитьКоличествоЭлементовВТранзакцииЗагрузкиДанныхПоУмолчанию() Экспорт
	
	Если Не ОбщегоНазначения.РазделениеВключено()
		И КоличествоЭлементовВТранзакцииЗагрузкиДанных() = 0 Тогда
		УстановитьКоличествоЭлементовВТранзакцииЗагрузкиДанных(1);
	КонецЕсли;
	
КонецПроцедуры

// Заполняет обработчик разделенных данных, зависимый от изменения неразделенных данных.
//
// Параметры:
//   Параметры - Структура - структура параметров обработчиков:
//     * РазделенныеОбработчики - см. ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления
// 
Процедура ЗаполнитьОбработчикиРазделенныхДанных(Параметры = Неопределено) Экспорт
	
	Если Параметры <> Неопределено Тогда
		Обработчики = Параметры.РазделенныеОбработчики;
		Обработчик = Обработчики.Добавить();
		Обработчик.Версия = "*";
		Обработчик.Процедура = "ОбменДаннымиСервер.УстановитьКодыПредопределенныхУзлов";
		Обработчик.РежимВыполнения = "Оперативно";
	КонецЕсли;
	
КонецПроцедуры

Процедура УстановитьКодыПредопределенныхУзлов() Экспорт
	
	КодИзМоделиСервиса = "";
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных()
		И ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность")
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		
		МодульРаботаВМоделиСервиса       = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
		
		КодИзМоделиСервиса = СокрЛП(МодульОбменДаннымиВМоделиСервиса.КодУзлаПланаОбменаВСервисе(МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса()));
	КонецЕсли;
	
	КоллекцияУзлов = Новый Массив;
	Для Каждого УзелСсылка Из ПредопределенныеУзлыПлановОбменаБСП() Цикл
		Если Не ЭтоПланОбменаXDTO(УзелСсылка) Тогда
			Продолжить;
		ИначеЕсли Не ОбменДаннымиXDTOСервер.ПоддерживаетсяВерсияСИдентификаторомОбменаДанными(УзелСсылка) Тогда
			Продолжить;
		КонецЕсли;
		
		КоллекцияУзлов.Добавить(УзелСсылка);
	КонецЦикла;
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных;
		Для Каждого УзелСсылка Из КоллекцияУзлов Цикл
			ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(УзелСсылка));
			ЭлементБлокировки.УстановитьЗначение("Ссылка", УзелСсылка);
		КонецЦикла;
		Блокировка.Заблокировать();
		
		ВиртуальныеКоды = РегистрыСведений.ПсевдонимыПредопределенныхУзлов.СоздатьНаборЗаписей();
		
		Для Каждого УзелСсылка Из КоллекцияУзлов Цикл
			
			КодПредопределенногоУзла = СокрЛП(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(УзелСсылка, "Код"));
			Если Не ЗначениеЗаполнено(КодПредопределенногоУзла)
				// Не был выполнен переход на новую кодировку узлов.
				Или СтрДлина(КодПредопределенногоУзла) < 36
				// Требуется перекодировка в связи с тем, что код сформирован по логике БТС.
				Или КодПредопределенногоУзла = КодИзМоделиСервиса Тогда
				
				УникальныйИдентификаторОбменаДанными = Строка(Новый УникальныйИдентификатор);
				
				ЗаблокироватьДанныеДляРедактирования(УзелСсылка);
				УзелОбъект = УзелСсылка.ПолучитьОбъект();
				
				УзелОбъект.Код = УникальныйИдентификаторОбменаДанными;
				УзелОбъект.ОбменДанными.Загрузка = Истина;
				УзелОбъект.Записать();
				
				Если ЗначениеЗаполнено(КодПредопределенногоУзла) Тогда
					// Сохранение предыдущего кода узла в регистре виртуальных кодов.
					ТекстЗапроса = 
					"ВЫБРАТЬ
					|	Т.Ссылка КАК Ссылка
					|ИЗ
					|	#ТаблицаПланаОбмена КАК Т
					|ГДЕ
					|	НЕ Т.ЭтотУзел
					|	И НЕ Т.ПометкаУдаления";
					
					ТекстЗапроса = СтрЗаменить(ТекстЗапроса,
						"#ТаблицаПланаОбмена", "ПланОбмена." + ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелСсылка));
					
					Запрос = Новый Запрос(ТекстЗапроса);
					
					КорреспондентыПланаОбмена = Запрос.Выполнить().Выбрать();
					Пока КорреспондентыПланаОбмена.Следующий() Цикл
						ВиртуальныйКод = ВиртуальныеКоды.Добавить();
						ВиртуальныйКод.Корреспондент = КорреспондентыПланаОбмена.Ссылка;
						ВиртуальныйКод.КодУзла       = КодПредопределенногоУзла;
					КонецЦикла;
				КонецЕсли;
				
			КонецЕсли;
		КонецЦикла;
		
		Если ВиртуальныеКоды.Количество() > 0 Тогда
			ВиртуальныеКоды.Записать();
		КонецЕсли;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Удаляет роль НастройкаСинхронизацииДанных из всех профилей, в которые она входит.
Процедура УдалитьРольНастройкаСинхронизацииДанных() Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		Возврат;
	КонецЕсли;
	
	МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
	
	НовыеРоли = Новый Массив;
	ЗаменяемыеРоли = Новый Соответствие;
	ЗаменяемыеРоли.Вставить("? НастройкаСинхронизацииДанных", НовыеРоли);
	
	МодульУправлениеДоступом.ЗаменитьРолиВПрофилях(ЗаменяемыеРоли);
	
КонецПроцедуры

Процедура НастроитьАрхивированиеСообщенийАРМ() Экспорт
	
	Если НЕ ЭтоАвтономноеРабочееМесто() Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		
		МодульАвтономнаяРаботаСлужебный = ОбщегоНазначения.ОбщийМодуль("АвтономнаяРаботаСлужебный");
		
		Узел = МодульАвтономнаяРаботаСлужебный.ПриложениеВСервисе();
		
		Если РегистрыСведений.НастройкиАрхиваСообщенийОбменов.ПолучитьНастройки(Узел) = Неопределено Тогда
			
			Настройки = РегистрыСведений.НастройкиАрхиваСообщенийОбменов.СоздатьМенеджерЗаписи();
			Настройки.УзелИнформационнойБазы = Узел;
			Настройки.КоличествоФайлов = 1;
			Настройки.ХранитьНаДиске = Ложь;
			Настройки.СжиматьФайлы = Истина;
			Настройки.Записать();  // АПК:1363 Настройки не участвуют в обмене 
			
		КонецЕсли;
	
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СообщенияОбменов

// Получает сообщение обмена во временный каталог пользователя ОС.
//
// Параметры:
//  Отказ                        - Булево - флаг отказа; поднимается в случае возникновения ошибки.
//  УзелИнформационнойБазы       - ПланОбменаСсылка - узел плана обмена, для которого выполняется получение сообщения
//                                                    обмена.
//  ВидТранспортаСообщенийОбмена - ПеречислениеСсылка.ВидыТранспортаСообщенийОбмена - вид транспорта для получения
//                                                                                    сообщения обмена.
//  ВыводитьСообщения            - Булево - если Истина, то выводятся сообщения пользователю.
//
//  Возвращаемое значение:
//   Структура со следующими ключи:
//     * ИмяВременногоКаталогаСообщенийОбмена - полное имя каталога обмена, в которое было загружено сообщение обмена.
//     * ИмяФайлаСообщенияОбмена              - полное имя файла сообщения обмена.
//     * ИдентификаторФайлаПакетаДанных       - дата изменения файла сообщения обмена.
//
Функция ПолучитьСообщениеОбменаВоВременныйКаталог(Отказ, УзелИнформационнойБазы, ВидТранспортаСообщенийОбмена, ВыводитьСообщения = Истина) Экспорт
	
	// Возвращаемое значение функции.
	Результат = Новый Структура;
	Результат.Вставить("ИмяВременногоКаталогаСообщенийОбмена", "");
	Результат.Вставить("ИмяФайлаСообщенияОбмена",              "");
	Результат.Вставить("ИдентификаторФайлаПакетаДанных",       Неопределено);
	
	СтруктураНастроекОбмена = НастройкиТранспортаОбмена(УзелИнформационнойБазы, ВидТранспортаСообщенийОбмена);
	
	СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено;
	
	// Если настройка содержит ошибки, то получение сообщения обмена не производим; статус "Отменено".
	Если СтруктураНастроекОбмена.Отказ Тогда
		
		Если ВыводитьСообщения Тогда
			НСтрока = НСтр("ru = 'При инициализации обработки транспорта сообщений обмена возникли ошибки.'");
			ОбщегоНазначения.СообщитьПользователю(НСтрока,,,, Отказ);
		КонецЕсли;
		
		ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
		Возврат Результат;
	КонецЕсли;
	
	// создаем временный каталог
	ВыполнитьТранспортСообщенияОбменаПередОбработкой(СтруктураНастроекОбмена);
	
	Если СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено Тогда
		
		// Получаем сообщение во временный каталог.
		ВыполнитьТранспортСообщенияОбменаПолучение(СтруктураНастроекОбмена);
		
	КонецЕсли;

	Если СтруктураНастроекОбмена.РезультатВыполненияОбмена <> Неопределено Тогда
		
		Если ВыводитьСообщения Тогда
			НСтрока = НСтр("ru = 'При получении сообщений обмена возникли ошибки.'");
			ОбщегоНазначения.СообщитьПользователю(НСтрока,,,, Отказ);
		КонецЕсли;
		
		// Удаляем временный каталог и все его содержимое.
		ВыполнитьТранспортСообщенияОбменаПослеОбработки(СтруктураНастроекОбмена);
		
		ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
		Возврат Результат;
	КонецЕсли;
	
	Результат.ИмяВременногоКаталогаСообщенийОбмена = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена.ИмяКаталогаСообщенияОбмена();
	Результат.ИмяФайлаСообщенияОбмена              = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена.ИмяФайлаСообщенияОбмена();
	Результат.ИдентификаторФайлаПакетаДанных       = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена.ДатаФайлаСообщенияОбмена();
	
	Возврат Результат;
КонецФункции

// Получает сообщение обмена из информационной базы корреспондента во временный каталог пользователя ОС.
//
// Параметры:
//  Отказ                        - Булево - флаг отказа; поднимается в случае возникновения ошибки.
//  УзелИнформационнойБазы       - ПланОбменаСсылка - узел плана обмена, для которого выполняется получение сообщения
//                                                    обмена.
//  ВыводитьСообщения            - Булево - если Истина, то выводятся сообщения пользователю.
//
//  Возвращаемое значение:
//   Структура со следующими ключи:
//     * ИмяВременногоКаталогаСообщенийОбмена - полное имя каталога обмена, в которое было загружено сообщение обмена.
//     * ИмяФайлаСообщенияОбмена              - полное имя файла сообщения обмена.
//     * ИдентификаторФайлаПакетаДанных       - дата изменения файла сообщения обмена.
//
Функция ПолучитьСообщениеОбменаВоВременныйКаталогИзИнформационнойБазыКорреспондента(Отказ, УзелИнформационнойБазы, ВыводитьСообщения = Истина) Экспорт
	
	// Возвращаемое значение функции.
	Результат = Новый Структура;
	Результат.Вставить("ИмяВременногоКаталогаСообщенийОбмена", "");
	Результат.Вставить("ИмяФайлаСообщенияОбмена",              "");
	Результат.Вставить("ИдентификаторФайлаПакетаДанных",       Неопределено);
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
	ИмяПланаОбменаКорреспондента = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбменаКорреспондента(УзелИнформационнойБазы);
	
	ТекущийУзелПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьЭтотУзелПланаОбмена(ИмяПланаОбмена);
	КодТекущегоУзлаПланаОбмена = ИдентификаторЭтогоУзлаДляОбмена(УзелИнформационнойБазы);

	ШаблонИмениФайлаСообщения = ШаблонИмениФайлаСообщения(ТекущийУзелПланаОбмена, УзелИнформационнойБазы, Ложь);
	
	// Параметры, которые будут определены в функции.
	ДатаФайлаСообщенияОбмена = Дата('00010101');
	ИмяКаталогаСообщенияОбмена = "";
	СтрокаСообщенияОбОшибке = "";
	
	Попытка
		ИмяКаталогаСообщенияОбмена = СоздатьВременныйКаталогСообщенийОбмена();
	Исключение
		Если ВыводитьСообщения Тогда
			Сообщение = НСтр("ru = 'Не удалось произвести обмен: %1'");
			Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение, 
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ОбщегоНазначения.СообщитьПользователю(Сообщение,,,, Отказ);
		КонецЕсли;
		Возврат Результат;
	КонецПопытки;
	
	// Получаем внешнее соединение для узла информационной базы.
	ДанныеСоединения = ОбменДаннымиПовтИсп.ВнешнееСоединениеДляУзлаИнформационнойБазы(УзелИнформационнойБазы);
	ВнешнееСоединение = ДанныеСоединения.Соединение;
	
	Если ВнешнееСоединение = Неопределено Тогда
		
		Сообщение = НСтр("ru = 'Не удалось произвести обмен: %1'");
		Если ВыводитьСообщения Тогда
			СообщениеДляПользователя = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение, ДанныеСоединения.КраткоеОписаниеОшибки);
			ОбщегоНазначения.СообщитьПользователю(СообщениеДляПользователя,,,, Отказ);
		КонецЕсли;
		
		// Добавляем две записи в ЖР: одну для загрузки данных, другую для выгрузки данных.
		СтруктураНастроекОбмена = Новый Структура("КлючСообщенияЖурналаРегистрации");
		СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации = КлючСообщенияЖурналаРегистрации(УзелИнформационнойБазы, Перечисления.ДействияПриОбмене.ЗагрузкаДанных);
		
		Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение, ДанныеСоединения.ПодробноеОписаниеОшибки);
		ЗаписьЖурналаРегистрацииОбменаДанными(Сообщение, СтруктураНастроекОбмена, Истина);
		
		Возврат Результат;
	КонецЕсли;
	
	ИмяФайлаСообщенияОбмена = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(ИмяКаталогаСообщенияОбмена, ШаблонИмениФайлаСообщения + ".xml");
	
	ПсевдонимУзла = ПсевдонимПредопределенногоУзла(УзелИнформационнойБазы);
	Если ЗначениеЗаполнено(ПсевдонимУзла) Тогда
		// Надо проверить код узла в корреспонденте - он может быть уже перекодирован.
		// Тогда псевдоним больше не нужен.
		ПланОбменаМенеджер = ВнешнееСоединение.ПланыОбмена[ИмяПланаОбменаКорреспондента];
		Если ПланОбменаМенеджер.НайтиПоКоду(ПсевдонимУзла) <> ПланОбменаМенеджер.ПустаяСсылка() Тогда
			КодТекущегоУзлаПланаОбмена = ПсевдонимУзла;
		КонецЕсли;
	КонецЕсли;
	
	ВнешнееСоединение.ОбменДаннымиВнешнееСоединение.ВыполнитьВыгрузкуДляУзлаИнформационнойБазы(Отказ, 
		ИмяПланаОбменаКорреспондента, КодТекущегоУзлаПланаОбмена, ИмяФайлаСообщенияОбмена, СтрокаСообщенияОбОшибке);
	
	Если Отказ Тогда
		
		Если ВыводитьСообщения Тогда
			// Выводим сообщение об ошибке.
			Сообщение = НСтр("ru = 'Не удалось выгрузить данные: %1'");
			Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение, ДанныеСоединения.КраткоеОписаниеОшибки);
			ОбщегоНазначения.СообщитьПользователю(Сообщение,,,, Отказ);
		КонецЕсли;
		
		Возврат Результат;
	КонецЕсли;
	
	ФайлСообщенияОбмена = Новый Файл(ИмяФайлаСообщенияОбмена);
	Если ФайлСообщенияОбмена.Существует() Тогда
		ДатаФайлаСообщенияОбмена = ФайлСообщенияОбмена.ПолучитьВремяИзменения();
	КонецЕсли;
	
	Результат.ИмяВременногоКаталогаСообщенийОбмена = ИмяКаталогаСообщенияОбмена;
	Результат.ИмяФайлаСообщенияОбмена              = ИмяФайлаСообщенияОбмена;
	Результат.ИдентификаторФайлаПакетаДанных       = ДатаФайлаСообщенияОбмена;
	
	Возврат Результат;
КонецФункции

// Выполняет удаление файлов сообщений обмена, которые не были удалены из-за сбоев в работе системы.
// Удалению подлежат файлы обмена с датой размещения более суток от текущей универсальной даты,
// и файлы для сопоставления с датой размещения более 7 суток от текущей универсальной даты.
// Анализируется РС.СообщенияОбменаДанными и РС.СообщенияОбменаДаннымиОбластейДанных.
//
// Параметры:
//   Нет.
//
Процедура УдалитьНеактуальныеСообщенияОбмена() Экспорт
	
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.УдалениеНеактуальнойИнформацииСинхронизации);
	
	Если Не ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюДанных") Тогда
		Возврат;
	КонецЕсли;
	
	ПроверитьВозможностьАдминистрированияОбменов();
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		// Удаляем неактуальные сообщения обмена, отмеченные в РС.СообщенияОбменаДанными.
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	СообщенияОбменаДанными.ИдентификаторСообщения КАК ИдентификаторСообщения,
		|	СообщенияОбменаДанными.ИмяФайлаСообщения КАК ИмяФайла,
		|	СообщенияОбменаДанными.ДатаЗакладкиСообщения КАК ДатаЗакладкиСообщения,
		|	ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	ВЫБОР
		|		КОГДА ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы ЕСТЬ NULL
		|			ТОГДА ЛОЖЬ
		|		ИНАЧЕ ИСТИНА
		|	КОНЕЦ КАК СообщениеДляСопоставления
		|ПОМЕСТИТЬ ВТСообщенияОбмена
		|ИЗ
		|	РегистрСведений.СообщенияОбменаДанными КАК СообщенияОбменаДанными
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ОбщиеНастройкиУзловИнформационныхБаз КАК ОбщиеНастройкиУзловИнформационныхБаз
		|		ПО (ОбщиеНастройкиУзловИнформационныхБаз.СообщениеДляСопоставленияДанных = СообщенияОбменаДанными.ИдентификаторСообщения)
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ВТСообщенияОбмена.ИдентификаторСообщения КАК ИдентификаторСообщения,
		|	ВТСообщенияОбмена.ИмяФайла КАК ИмяФайла,
		|	ВТСообщенияОбмена.СообщениеДляСопоставления КАК СообщениеДляСопоставления,
		|	ВТСообщенияОбмена.УзелИнформационнойБазы КАК УзелИнформационнойБазы
		|ИЗ
		|	ВТСообщенияОбмена КАК ВТСообщенияОбмена
		|ГДЕ
		|	ВЫБОР
		|			КОГДА ВТСообщенияОбмена.СообщениеДляСопоставления
		|				ТОГДА ВТСообщенияОбмена.ДатаЗакладкиСообщения < &ДатаАктуальностиДляСопоставления
		|			ИНАЧЕ ВТСообщенияОбмена.ДатаЗакладкиСообщения < &ДатаАктуальности
		|		КОНЕЦ";
		
		Запрос = Новый Запрос;
		Запрос.УстановитьПараметр("ДатаАктуальности",                 ТекущаяУниверсальнаяДата() - 60 * 60 * 24);
		Запрос.УстановитьПараметр("ДатаАктуальностиДляСопоставления", ТекущаяУниверсальнаяДата() - 60 * 60 * 24 * 7);
		Запрос.Текст = ТекстЗапроса;
		
		Выборка = Запрос.Выполнить().Выбрать();
		
		Пока Выборка.Следующий() Цикл
			
			ПолноеИмяФайлаСообщения = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременногоХранилищаФайлов(), Выборка.ИмяФайла);
			
			ФайлСообщения = Новый Файл(ПолноеИмяФайлаСообщения);
			
			Если ФайлСообщения.Существует() Тогда
				
				Попытка
					УдалитьФайлы(ФайлСообщения.ПолноеИмя);
				Исключение
					ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(),
						УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
					Продолжить;
				КонецПопытки;
			КонецЕсли;
			
			// Удаляем информацию о файле сообщения обмена из хранилища.
			СтруктураЗаписи = Новый Структура;
			СтруктураЗаписи.Вставить("ИдентификаторСообщения", Строка(Выборка.ИдентификаторСообщения));
			РегистрыСведений.СообщенияОбменаДанными.УдалитьЗапись(СтруктураЗаписи);
			
			Если Выборка.СообщениеДляСопоставления Тогда
				СтруктураЗаписи = Новый Структура;
				СтруктураЗаписи.Вставить("УзелИнформационнойБазы",          Выборка.УзелИнформационнойБазы);
				СтруктураЗаписи.Вставить("СообщениеДляСопоставленияДанных", "");
				
				ОбменДаннымиСлужебный.ОбновитьЗаписьВРегистрСведений(СтруктураЗаписи, "ОбщиеНастройкиУзловИнформационныхБаз");
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЕсли;
	
	// Удаляем неактуальные сообщения обмена, отмеченные в РС.СообщенияОбменаДаннымиОбластейДанных.
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
		МодульОбменДаннымиВМоделиСервиса.ПриУдаленииНеактуальныхСообщенийОбмена();
	КонецЕсли;
	
КонецПроцедуры

// Выполняет выгрузку сообщения обмена, которое содержало
// изменения конфигурации, до обновления информационной базы.
//
Процедура ВыгрузитьСообщениеПослеОбновленияИнформационнойБазы()
	
	// После успешной загрузки и обновления ИБ режим повтора можно отключить.
	ОтключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском();
	
	Попытка
		Если ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюДанных") Тогда
			
			УзелИнформационнойБазы = ГлавныйУзел();
			
			Если УзелИнформационнойБазы <> Неопределено Тогда
				
				ВыполнитьВыгрузку = Истина;
				
				НастройкиТранспорта = РегистрыСведений.НастройкиТранспортаОбменаДанными.НастройкиТранспорта(УзелИнформационнойБазы);
				
				ВидТранспорта = НастройкиТранспорта.ВидТранспортаСообщенийОбменаПоУмолчанию;
				
				Если ВидТранспорта = Перечисления.ВидыТранспортаСообщенийОбмена.WS
					И Не НастройкиТранспорта.WSЗапомнитьПароль Тогда
					
					ВыполнитьВыгрузку = Ложь;
					
					РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.УстановитьПризнакОтправкиДанных(УзелИнформационнойБазы);
					
				КонецЕсли;
				
				Если ВыполнитьВыгрузку Тогда
					
					// Только выгрузка.
					Отказ = Ложь;
					
					ПараметрыОбмена = ПараметрыОбмена();
					ПараметрыОбмена.ВидТранспортаСообщенийОбмена = ВидТранспорта;
					ПараметрыОбмена.ВыполнятьЗагрузку = Ложь;
					ПараметрыОбмена.ВыполнятьВыгрузку = Истина;
					
					ВыполнитьОбменДаннымиДляУзлаИнформационнойБазы(УзелИнформационнойБазы, ПараметрыОбмена, Отказ);
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
		
	Исключение
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(),
			УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	
КонецПроцедуры

#КонецОбласти

#Область ВыполнениеОбменаМетодамиСериализации

// Процедура записи изменений для сообщения обмена.
// Применима для случаев когда структура метаданных обменивающихся баз одинакова для всех объектов участвующих в обмене.
//
Процедура ВыполнитьСтандартнуюВыгрузкуИзмененийДляУзла(Отказ,
							УзелИнформационнойБазы,
							ИмяФайла,
							СообщениеОбмена,
							КоличествоЭлементовВТранзакции = 0,
							КлючСообщенияЖурналаРегистрации = "",
							КоличествоОбъектовОбработано = 0)
	
	ЗаписьXML = Новый ЗаписьXML;	
	Если Не ПустаяСтрока(ИмяФайла) Тогда
		ЗаписьXML.ОткрытьФайл(ИмяФайла);
	Иначе
		ЗаписьXML.УстановитьСтроку();
	КонецЕсли;
	ЗаписьXML.ЗаписатьОбъявлениеXML();
	
	// Создаем новое сообщение.
	ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
	
	ЗаписьСообщения.НачатьЗапись(ЗаписьXML, УзелИнформационнойБазы);
	
	ОбменДаннымиСлужебный.ПроверитьКэшМеханизмаРегистрацииОбъектов();
	
	ТаблицаПредопределенных = ОбменДаннымиСлужебный.ТаблицаПредопределенныхДанных();
	ТаблицаПредопределенных.Колонки.Добавить("Выгружать", Новый ОписаниеТипов("Булево"));
	ТаблицаПредопределенных.Индексы.Добавить("Ссылка");
	
	// Получаем выборку измененных данных.
	ВыборкаИзменений = ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения);
	
	Если ПустаяСтрока(КлючСообщенияЖурналаРегистрации) Тогда
		КлючСообщенияЖурналаРегистрации = СобытиеЖурналаРегистрацииОбменДанными();
	КонецЕсли;
	
	ПолучательОбъект = УзелИнформационнойБазы.ПолучитьОбъект();
	
	ПараметрыВыгрузки = Новый Структура;
	ПараметрыВыгрузки.Вставить("ЗаписьXML",                      ЗаписьXML);
	ПараметрыВыгрузки.Вставить("Получатель",                     ПолучательОбъект);
	ПараметрыВыгрузки.Вставить("НачальнаяВыгрузкаДанных",        УстановленПризнакНачальнойВыгрузкиДанных(УзелИнформационнойБазы));
	ПараметрыВыгрузки.Вставить("КоличествоЭлементовВТранзакции", КоличествоЭлементовВТранзакции);
	ПараметрыВыгрузки.Вставить("КоличествоОбъектовОбработано",   КоличествоОбъектовОбработано);
	ПараметрыВыгрузки.Вставить("ТаблицаПредопределенных",        ТаблицаПредопределенных);
	
	ИспользоватьТранзакции = КоличествоЭлементовВТранзакции <> 1;
	
	ПродолжитьВыгрузку = Истина;
	Если ИспользоватьТранзакции Тогда
		Пока ПродолжитьВыгрузку Цикл
			НачатьТранзакцию();
			Попытка
				ВыполнитьСтандартнуюВыгрузкуПорцииДанных(ВыборкаИзменений, ПараметрыВыгрузки, ПродолжитьВыгрузку);
				ЗафиксироватьТранзакцию();
			Исключение
				ОтменитьТранзакцию();
				
				ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
					УзелИнформационнойБазы.Метаданные(), УзелИнформационнойБазы,
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				Отказ = Истина;
				Прервать;
			КонецПопытки;
		КонецЦикла;
	Иначе
		Попытка
			Пока ПродолжитьВыгрузку Цикл
				ВыполнитьСтандартнуюВыгрузкуПорцииДанных(ВыборкаИзменений, ПараметрыВыгрузки, ПродолжитьВыгрузку);
			КонецЦикла;
		Исключение
			ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
				УзелИнформационнойБазы.Метаданные(), УзелИнформационнойБазы, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			Отказ = Истина;
		КонецПопытки;
	КонецЕсли;
	
	Если Отказ Тогда
		ЗаписьСообщения.ПрерватьЗапись();
		ЗаписьXML.Закрыть();
		Возврат;
	КонецЕсли;
	
	ВыгрузитьТаблицуПредопределенных(ПараметрыВыгрузки);
	
	ЗаписьСообщения.ЗакончитьЗапись();
	СообщениеОбмена = ЗаписьXML.Закрыть();
	
	КоличествоОбъектовОбработано = ПараметрыВыгрузки.КоличествоОбъектовОбработано;
	
КонецПроцедуры

Процедура ВыполнитьСтандартнуюВыгрузкуПорцииДанных(ВыборкаИзменений, ПараметрыВыгрузки, ПродолжитьВыгрузку)
	
	КоличествоЗаписанных = 0;
	
	Пока (ПараметрыВыгрузки.КоличествоЭлементовВТранзакции = 0
			Или КоличествоЗаписанных <= ПараметрыВыгрузки.КоличествоЭлементовВТранзакции)
		И ВыборкаИзменений.Следующий() Цикл
		
		Данные = ВыборкаИзменений.Получить();
		
		// Выполняем проверку на то, что объект проходит фильтр ПРО
		// если объект фильтр ПРО не проходит, то в базу-приемник отсылаем удаление объекта
		// для наборов записей выполняем фильтрацию каждой записи
		// наборы выгружаем всегда, даже пустые (аналог удаления объекта).
		ОтправкаЭлемента = ОтправкаЭлементаДанных.Авто;
		
		СтандартныеПодсистемыСервер.ПриОтправкеДанныхПодчиненному(Данные, ОтправкаЭлемента, ПараметрыВыгрузки.НачальнаяВыгрузкаДанных, ПараметрыВыгрузки.Получатель);
		
		Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить Тогда
			
			Если ОбщегоНазначения.ЭтоРегистр(Данные.Метаданные()) Тогда
				
				// Удаление регистра отсылаем в виде пустого набора записей.
				
			Иначе
				
				Данные = Новый УдалениеОбъекта(Данные.Ссылка);
				
			КонецЕсли;
			
		ИначеЕсли ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		// Записываем данные в сообщение.
		ЗаписатьXML(ПараметрыВыгрузки.ЗаписьXML, Данные);
		КоличествоЗаписанных = КоличествоЗаписанных + 1;
		
		ОбменДаннымиСлужебный.ОтметитьСсылкиНаПредопределенныеДанные(Данные, ПараметрыВыгрузки.ТаблицаПредопределенных);
		
	КонецЦикла;
	
	ПродолжитьВыгрузку = (КоличествоЗаписанных > 0);
	
	ПараметрыВыгрузки.КоличествоОбъектовОбработано = ПараметрыВыгрузки.КоличествоОбъектовОбработано + КоличествоЗаписанных;
	
КонецПроцедуры

Процедура ВыгрузитьТаблицуПредопределенных(ПараметрыВыгрузки)
	
	ПараметрыВыгрузки.ТаблицаПредопределенных.Сортировать("ИмяТаблицы");
	
	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку("UTF-8");
	
	ЗаписьXML.ЗаписатьНачалоЭлемента("PredefinedData");
	
	КоличествоВыгружено = 0;
	
	Для Каждого СтрокаПредопределенных Из ПараметрыВыгрузки.ТаблицаПредопределенных Цикл
		Если Не СтрокаПредопределенных.Выгружать Тогда
			Продолжить;
		КонецЕсли;
		
		ЗаписьXML.ЗаписатьНачалоЭлемента(СтрокаПредопределенных.ИмяТипаXML);
		ЗаписьXML.ЗаписатьАтрибут("PredefinedDataName", СтрокаПредопределенных.ИмяПредопределенныхДанных);
		ЗаписьXML.ЗаписатьТекст(XMLСтрока(СтрокаПредопределенных.Ссылка));
		ЗаписьXML.ЗаписатьКонецЭлемента();
		
		КоличествоВыгружено = КоличествоВыгружено + 1;
	КонецЦикла;
	
	ЗаписьXML.ЗаписатьКонецЭлемента(); // PredefinedData
	
	КомментарийПредопределенные = ЗаписьXML.Закрыть();
	
	Если КоличествоВыгружено > 0 Тогда
		ПараметрыВыгрузки.ЗаписьXML.ЗаписатьКомментарий(КомментарийПредопределенные);
	КонецЕсли;
	
КонецПроцедуры

// Процедура чтения изменений из сообщения обмена.
// Применима для случаев когда структура метаданных обменивающихся баз одинакова для всех объектов участвующих в обмене.
//
Процедура ВыполнитьСтандартнуюЗагрузкуИзмененийДляУзла(
		УзелИнформационнойБазы,
		ИмяФайла,
		СообщениеОбмена,
		КоличествоЭлементовВТранзакции,
		КлючСообщенияЖурналаРегистрации,
		КоличествоОбъектовОбработано,
		РезультатВыполненияОбмена)
		
	Если ПустаяСтрока(КлючСообщенияЖурналаРегистрации) Тогда
		КлючСообщенияЖурналаРегистрации = СобытиеЖурналаРегистрацииОбменДанными();
	КонецЕсли;
	
	ПараметрыЗагрузки = Новый Структура;
	ПараметрыЗагрузки.Вставить("УзелИнформационнойБазы",       УзелИнформационнойБазы);
	ПараметрыЗагрузки.Вставить("СообщениеОбмена",              СообщениеОбмена);
	ПараметрыЗагрузки.Вставить("ИмяФайла",                     ИмяФайла);
	ПараметрыЗагрузки.Вставить("ЧтениеXML",                    Неопределено);
	ПараметрыЗагрузки.Вставить("ЧтениеСообщения",              Неопределено);
	
	ПараметрыЗагрузки.Вставить("КоличествоЭлементовВТранзакции", КоличествоЭлементовВТранзакции);
	ПараметрыЗагрузки.Вставить("КоличествоОбъектовОбработано",   0);
	
	ТаблицаПредопределенных = ОбменДаннымиСлужебный.ТаблицаПредопределенныхДанных();
	ТаблицаПредопределенных.Колонки.Добавить("ИсходнаяСсылка");
	ТаблицаПредопределенных.Колонки.Добавить("ИсходнаяСсылкаЗаполнена", Новый ОписаниеТипов("Булево"));
	
	ПараметрыЗагрузки.Вставить("ТаблицаПредопределенных", ТаблицаПредопределенных);
	
	СообщениеОбОшибке = "";
	ЗаполнитьИсходныеСсылкиВТаблицеПредопределенныхДанных(ПараметрыЗагрузки, СообщениеОбОшибке);
	
	ПараметрыЗагрузки.ТаблицаПредопределенных = ТаблицаПредопределенных.Скопировать(Новый Структура("ИсходнаяСсылкаЗаполнена", Истина));
	ПараметрыЗагрузки.ТаблицаПредопределенных.Индексы.Добавить("ИсходнаяСсылка");
	ТаблицаПредопределенных = Неопределено;
	
	Если Не ПустаяСтрока(СообщениеОбОшибке) Тогда
		ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Предупреждение,
			УзелИнформационнойБазы.Метаданные(), УзелИнформационнойБазы, СообщениеОбОшибке);
	КонецЕсли;
	
	ИнициализироватьЧтениеСообщенияДляСтандартнойЗагрузки(ПараметрыЗагрузки, РезультатВыполненияОбмена, СообщениеОбОшибке);
	
	Если РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка Тогда
		ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
			УзелИнформационнойБазы.Метаданные(), УзелИнформационнойБазы, СообщениеОбОшибке);
		Возврат;
	ИначеЕсли РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Предупреждение_СообщениеОбменаБылоРанееПринято Тогда
		ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Предупреждение,
			УзелИнформационнойБазы.Метаданные(), УзелИнформационнойБазы, СообщениеОбОшибке);
		Возврат;
	КонецЕсли;
	
	ЧтениеXML       = ПараметрыЗагрузки.ЧтениеXML;
	ЧтениеСообщения = ПараметрыЗагрузки.ЧтениеСообщения;
	
	ПараметрыРезервнойКопии = ПараметрыРезервнойКопии(ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);
	
	// Удаление регистрации изменений для узла отправителя сообщения.
	Если Не ПараметрыРезервнойКопии.ВосстановленаРезервнаяКопия Тогда
		ПланыОбмена.УдалитьРегистрациюИзменений(ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);
		РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.СнятьПризнакНачальнойВыгрузкиДанных(
			ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);
	КонецЕсли;
		
	ИспользоватьТранзакции = КоличествоЭлементовВТранзакции <> 1;
	
	ПродолжитьЗагрузку = Истина;
	Если ИспользоватьТранзакции Тогда
		Пока ПродолжитьЗагрузку Цикл
			ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Истина);
			НачатьТранзакцию();
			Попытка
				ВыполнитьСтандартнуюЗагрузкуПорцииДанных(ПараметрыЗагрузки, ПродолжитьЗагрузку);
				ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Ложь);
				ЗафиксироватьТранзакцию();
			Исключение
				ОтменитьТранзакцию();
				ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Ложь, Ложь);
				
				РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
				ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
					УзелИнформационнойБазы.Метаданные(), УзелИнформационнойБазы,
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				Прервать;
			КонецПопытки;
		КонецЦикла;
	Иначе
		ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Истина);
		Попытка
			Пока ПродолжитьЗагрузку Цикл
				ВыполнитьСтандартнуюЗагрузкуПорцииДанных(ПараметрыЗагрузки, ПродолжитьЗагрузку);
			КонецЦикла;
			ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Ложь);
		Исключение
			ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Ложь);
			РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
			ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
				УзелИнформационнойБазы.Метаданные(), УзелИнформационнойБазы,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		
	КонецЕсли;
	
	Если РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка Тогда
		ЧтениеСообщения.ПрерватьЧтение();
	Иначе
		// Пропуск всех не стандартных элементов в теле сообщения.
		ТекущееИмяУзла = "";
		Пока ЧтениеСообщения.ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента
			Или (ЧтениеСообщения.ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента
				И ЧтениеСообщения.ЧтениеXML.Имя = ТекущееИмяУзла) Цикл
			ТекущееИмяУзла = ЧтениеСообщения.ЧтениеXML.Имя;
			ЧтениеСообщения.ЧтениеXML.Пропустить();
		КонецЦикла;
		
		Попытка
			ЧтениеСообщения.ЗакончитьЧтение();
			ПриВосстановленииРезервнойКопии(ПараметрыРезервнойКопии);
		Исключение
			РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
			ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка,
				УзелИнформационнойБазы.Метаданные(), УзелИнформационнойБазы,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
	КонецЕсли;
	
	ЧтениеXML.Закрыть();
	
	КоличествоОбъектовОбработано = ПараметрыЗагрузки.КоличествоОбъектовОбработано;
	
КонецПроцедуры

Процедура ЗаполнитьИсходныеСсылкиВТаблицеПредопределенныхДанных(ПараметрыЗагрузки, СообщениеОбОшибке)
	
	ЧтениеXML = Новый ЧтениеXML;
	ПараметрыЧтения = Новый ПараметрыЧтенияXML(, , , , , , , Ложь); // чтение с учетом комментариев
	Попытка
		Если Не ПустаяСтрока(ПараметрыЗагрузки.СообщениеОбмена) Тогда
			ЧтениеXML.УстановитьСтроку(ПараметрыЗагрузки.СообщениеОбмена, ПараметрыЧтения);
		Иначе
			ЧтениеXML.ОткрытьФайл(ПараметрыЗагрузки.ИмяФайла, ПараметрыЧтения);
		КонецЕсли;
		
		ЭтоBody = Ложь;
		Пока ЧтениеXML.Прочитать() Цикл
			Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
				Если ЧтениеXML.ЛокальноеИмя = "Message" Тогда
					Продолжить;
				ИначеЕсли ЧтениеXML.ЛокальноеИмя = "Header" Тогда
					ЧтениеXML.Пропустить();
				ИначеЕсли ЧтениеXML.ЛокальноеИмя = "Body" Тогда
					ЭтоBody = Истина;
					Продолжить;
				ИначеЕсли ЭтоBody И ВозможностьЧтенияXML(ЧтениеXML) Тогда
					ЧтениеXML.Пропустить();
				ИначеЕсли ЭтоBody И ЧтениеXML.ЛокальноеИмя = "PredefinedData" Тогда
					ОбработатьСекциюПредопределенныхДанныхВСообщенииОбмена(
						ЧтениеXML, ПараметрыЗагрузки.ТаблицаПредопределенных);
				КонецЕсли;
			ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
				Если ЧтениеXML.ЛокальноеИмя = "Message" Тогда
					Прервать;
				ИначеЕсли ЧтениеXML.ЛокальноеИмя = "Header" Тогда
					Продолжить;
				ИначеЕсли ЧтениеXML.ЛокальноеИмя = "Body" Тогда
					Прервать;
				КонецЕсли;
			ИначеЕсли ЭтоBody И ЧтениеXML.ТипУзла = ТипУзлаXML.Комментарий Тогда
				ЧтениеXMLКомментарий = Новый ЧтениеXML;
				ЧтениеXMLКомментарий.УстановитьСтроку(ЧтениеXML.Значение);
				ЧтениеXMLКомментарий.Прочитать(); // PredefinedData - НачалоЭлемента
				
				ОбработатьСекциюПредопределенныхДанныхВСообщенииОбмена(
					ЧтениеXMLКомментарий, ПараметрыЗагрузки.ТаблицаПредопределенных);
					
				ЧтениеXMLКомментарий.Закрыть();
			КонецЕсли;
		КонецЦикла;
	Исключение
		СообщениеОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;
	
	ЧтениеXML.Закрыть();
	
КонецПроцедуры

Процедура ИнициализироватьЧтениеСообщенияДляСтандартнойЗагрузки(ПараметрыЗагрузки, РезультатВыполненияОбмена, СообщениеОбОшибке)
	
	ЧтениеXML = Новый ЧтениеXML;
	Попытка
		Если Не ПустаяСтрока(ПараметрыЗагрузки.СообщениеОбмена) Тогда
			ЧтениеXML.УстановитьСтроку(ПараметрыЗагрузки.СообщениеОбмена);
		Иначе
			ЧтениеXML.ОткрытьФайл(ПараметрыЗагрузки.ИмяФайла);
		КонецЕсли;
		
		ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
		ЧтениеСообщения.НачатьЧтение(ЧтениеXML, ДопустимыйНомерСообщения.Больший);
	Исключение
		ИнформацияОбОшибке  = ИнформацияОбОшибке();
		
		КраткаяИнформация   = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
		ПодробнаяИнформация = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
		
		Если ЭтоОшибкаНомерСообщенияМеньшеИлиРавенНомеруРанееПринятогоСообщения(КраткаяИнформация) Тогда
			РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Предупреждение_СообщениеОбменаБылоРанееПринято;
			СообщениеОбОшибке = КраткаяИнформация;
		Иначе
			РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
			СообщениеОбОшибке = ПодробнаяИнформация;
		КонецЕсли;
		
		Возврат;
	КонецПопытки;
	
	Если ЧтениеСообщения.Отправитель <> ПараметрыЗагрузки.УзелИнформационнойБазы Тогда
		// Сообщение предназначено не для этого узла.
		РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
		
		СообщениеОбОшибке = НСтр("ru = 'Сообщение обмена содержит данные для другого узла информационной базы.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		Возврат;
	КонецЕсли;
	
	ПараметрыЗагрузки.ЧтениеXML       = ЧтениеXML;
	ПараметрыЗагрузки.ЧтениеСообщения = ЧтениеСообщения;
	
КонецПроцедуры

Процедура ВыполнитьСтандартнуюЗагрузкуПорцииДанных(ПараметрыЗагрузки, ПродолжитьЗагрузку)
	
	ЧтениеXML       = ПараметрыЗагрузки.ЧтениеXML;
	ЧтениеСообщения = ПараметрыЗагрузки.ЧтениеСообщения; // ЧтениеСообщенияОбмена
	
	КоличествоЗаписанных = 0;
	
	Пока (ПараметрыЗагрузки.КоличествоЭлементовВТранзакции = 0
			Или КоличествоЗаписанных <= ПараметрыЗагрузки.КоличествоЭлементовВТранзакции)
		И ВозможностьЧтенияXML(ЧтениеXML) Цикл
		
		Данные = ПрочитатьXML(ЧтениеXML);
		
		ПолучениеЭлемента = ПолучениеЭлементаДанных.Авто;
		ОтправкаНазад = Ложь;
		
		СтандартныеПодсистемыСервер.ПриПолученииДанныхОтГлавного(
			Данные, ПолучениеЭлемента, ОтправкаНазад, ЧтениеСообщения.Отправитель.ПолучитьОбъект());
			
		ПараметрыЗагрузки.КоличествоОбъектовОбработано = ПараметрыЗагрузки.КоличествоОбъектовОбработано + 1;
		
		Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
			Продолжить;
		КонецЕсли;
			
		// Переопределяем стандартное поведение системы при получении удаления объекта.
		// Вместо физического удаления объекта без контроля ссылочной целостности 
		// выполняем установку пометки на удаление.
		Если ТипЗнч(Данные) = Тип("УдалениеОбъекта") Тогда
			Данные = Данные.Ссылка.ПолучитьОбъект();
			
			Если Данные = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			Данные.ПометкаУдаления = Истина;
			
			Если ОбщегоНазначения.ЭтоДокумент(Данные.Метаданные()) Тогда
				Данные.Проведен = Ложь;
			КонецЕсли;
		Иначе
			ОбменДаннымиСлужебный.ЗаменитьСсылкиНаПредопределенныеЭлементы(Данные, ПараметрыЗагрузки.ТаблицаПредопределенных);
		КонецЕсли;
		
		Если Не ОтправкаНазад Тогда
			Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель;
		КонецЕсли;
		Данные.ОбменДанными.Загрузка = Истина;
		
		Данные.Записать();
		
		КоличествоЗаписанных = КоличествоЗаписанных + 1;
		
	КонецЦикла;
	
	ПродолжитьЗагрузку = (КоличествоЗаписанных > 0);
	
КонецПроцедуры

Процедура ОбработатьСекциюПредопределенныхДанныхВСообщенииОбмена(ЧтениеXML, ТаблицаПредопределенных)
	
	Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента
		И ЧтениеXML.ЛокальноеИмя = "PredefinedData" Тогда
		
		ЧтениеXML.Прочитать();
		Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
			ИмяТипаXML          = ЧтениеXML.ЛокальноеИмя;
			ИмяПредопределенных = ЧтениеXML.ПолучитьАтрибут("PredefinedDataName");
			ИсходнаяСсылка      = ПрочитатьXML(ЧтениеXML);
			
			СтрокиПредопределенные = ТаблицаПредопределенных.НайтиСтроки(
				Новый Структура("ИмяТипаXML, ИмяПредопределенныхДанных", ИмяТипаXML, ИмяПредопределенных));
			Для Каждого СтрокаПредопределенные Из СтрокиПредопределенные Цикл
				СтрокаПредопределенные.ИсходнаяСсылка = ИсходнаяСсылка;
				СтрокаПредопределенные.ИсходнаяСсылкаЗаполнена = Истина;
			КонецЦикла;
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ФункцииСвойства

Функция ПолноеИмяФайлаДанныхОтложенногоОбновления()
	
	Возврат ПолучитьИмяВременногоФайла(".xml");
	
КонецФункции

// Возвращает имя файла сообщения обмена данными по данным узла-отправителя и узла-получателя.
//
Функция ИмяФайлаСообщенияОбмена(КодУзлаОтправителя, КодУзлаПолучателя, ЭтоИсходящееСообщение)
	
	ШаблонИмени = "[Префикс]_[УзелОтправитель]_[УзелПолучатель]";
	Если СтрДлина(КодУзлаОтправителя) = 36 И ЭтоИсходящееСообщение Тогда
		ПрефиксИБИсточника = Константы.ПрефиксУзлаРаспределеннойИнформационнойБазы.Получить();
		Если ЗначениеЗаполнено(ПрефиксИБИсточника) Тогда
			ШаблонИмени = "[Префикс]_[ПрефиксИБИсточника]_[УзелОтправитель]_[УзелПолучатель]";
		КонецЕсли;
	КонецЕсли;
	ШаблонИмени = СтрЗаменить(ШаблонИмени, "[Префикс]",         "Message");
	ШаблонИмени = СтрЗаменить(ШаблонИмени, "[ПрефиксИБИсточника]",ПрефиксИБИсточника);
	ШаблонИмени = СтрЗаменить(ШаблонИмени, "[УзелОтправитель]", КодУзлаОтправителя);
	ШаблонИмени = СтрЗаменить(ШаблонИмени, "[УзелПолучатель]",  КодУзлаПолучателя);
	
	Возврат ШаблонИмени;
КонецФункции

// Возвращает имя временного каталога для сообщений обмена данными.
// Имя каталога соответствует шаблону:
// "Exchange82 {GUID}", 
// где GUID - строка уникального идентификатора.
//
// Параметры:
//  Нет.
// 
// Возвращаемое значение:
//  Строка - имя временного каталога для сообщений обмена данными.
//
Функция ИмяВременногоКаталогаСообщенийОбмена()
	
	Возврат СтрЗаменить("Exchange82 {GUID}", "GUID", ВРег(Строка(Новый УникальныйИдентификатор)));
	
КонецФункции

// Возвращает имя обработки транспорта сообщений обмена.
//
// Параметры:
//  ВидТранспорта - ПеречислениеСсылка.ВидыТранспортаСообщенийОбмена - вид транспорта, для которого необходимо получить
//                                                                     имя обработки.
// 
//  Возвращаемое значение:
//    Строка - имя обработки транспорта сообщений обмена.
//
Функция ИмяОбработкиТранспортаСообщенийОбмена(ВидТранспорта)
	
	ВидыТранспортаИОбработки = Новый Соответствие();
	ВидыТранспортаИОбработки.Вставить(Перечисления.ВидыТранспортаСообщенийОбмена.EMAIL,	Метаданные.Обработки.ТранспортСообщенийОбменаEMAIL.Имя);
	ВидыТранспортаИОбработки.Вставить(Перечисления.ВидыТранспортаСообщенийОбмена.FILE,	Метаданные.Обработки.ТранспортСообщенийОбменаFILE.Имя);
	ВидыТранспортаИОбработки.Вставить(Перечисления.ВидыТранспортаСообщенийОбмена.FTP,	Метаданные.Обработки.ТранспортСообщенийОбменаFTP.Имя);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ОбменДаннымиСВнешнимиСистемами") Тогда
		ВидыТранспортаИОбработки.Вставить(Перечисления.ВидыТранспортаСообщенийОбмена.ВнешняяСистема, "ТранспортСообщенийОбменаВнешняяСистема");
	КонецЕсли;
	
	Возврат ВидыТранспортаИОбработки.Получить(ВидТранспорта);
		
КонецФункции

// Дубль процедуры на сервере ОбменДаннымиКлиент.МаксимальноеКоличествоПолейСопоставленияОбъектов().
//
// Возвращаемое значение:
//   Число
//
Функция МаксимальноеКоличествоПолейСопоставленияОбъектов() Экспорт
	
	Возврат 5;
	
КонецФункции

// Функция-свойство: возвращает литерал обозначения строки неограниченной длины.
//
// Возвращаемое значение:
//  Строка - литерал обозначения строки неограниченной длины.
//
Функция СтрокаНеограниченнойДлины() Экспорт
	
	Возврат "(снд)";
	
КонецФункции

// Функция-свойство: возвращает литерал обозначения узла-XML, который содержит значение константы ПРО.
//
// Возвращаемое значение:
//  Строка - литерал обозначения узла-XML, который содержит значение константы ПРО.
//
Функция ЭлементОтбораСвойствоЗначениеКонстанты() Экспорт
	
	Возврат "ЗначениеКонстанты";
	
КонецФункции

// Функция-свойство: возвращает литерал обозначения узла-XML, который содержит алгоритм получения значения.
//
// Возвращаемое значение:
//  Строка - возвращает литерал обозначения узла-XML, который содержит алгоритм получения значения.
//
Функция ЭлементОтбораСвойствоАлгоритмЗначения() Экспорт
	
	Возврат "АлгоритмЗначения";
	
КонецФункции

// Функция-свойство: возвращает имя файла, который используется для проверки подключения обработки транспорта.
//
// Возвращаемое значение:
//  Строка - возвращает имя файла, который используется для проверки подключения обработки транспорта.
//
Функция ИмяВременногоФайлаПроверкиПодключения() Экспорт
	ПостфиксФайла = Строка(Новый УникальныйИдентификатор());
	Возврат "ConnectionCheckFile_" + ПостфиксФайла + ".tmp";
	
КонецФункции

Функция ЭтоОшибкаНомерСообщенияМеньшеИлиРавенНомеруРанееПринятогоСообщения(ОписаниеОшибки)
	
	Возврат СтрНайти(НРег(ОписаниеОшибки), НРег(НСтр("ru = 'Номер сообщения меньше или равен'"))) > 0;
	
КонецФункции

#КонецОбласти

#Область ТранспортСообщенийОбмена

Процедура ВыполнитьТранспортСообщенияОбменаПередОбработкой(СтруктураНастроекОбмена)
	
	// Получаем инициализированную обработку транспорта сообщений.
	ОбработкаТранспортаСообщенийОбмена = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена;
	
	// Получаем новое имя временного файла.
	Если Не ОбработкаТранспортаСообщенийОбмена.ВыполнитьДействияПередОбработкойСообщения() Тогда
		
		ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаТранспортаСообщенийОбмена.СтрокаСообщенияОбОшибкеЖР, СтруктураНастроекОбмена, Истина);
		
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьТранспортСообщенияОбменаОтправка(СтруктураНастроекОбмена)
	
	// Получаем инициализированную обработку транспорта сообщений.
	ОбработкаТранспортаСообщенийОбмена = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена;
	
	// Отправляем сообщение обмена из временного каталога.
	Если Не ОбработкаТранспортаСообщенийОбмена.ПодключениеУстановлено()
		Или Не ОбработкаТранспортаСообщенийОбмена.ОтправитьСообщение() Тогда
		
		ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаТранспортаСообщенийОбмена.СтрокаСообщенияОбОшибкеЖР, СтруктураНастроекОбмена, Истина);
		
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьТранспортСообщенияОбменаПолучение(СтруктураНастроекОбмена, ИспользоватьПсевдоним = Истина, СтекОшибок = Неопределено)
	
	Если СтекОшибок = Неопределено Тогда
		СтекОшибок = Новый Массив;
	КонецЕсли;
	
	// Получаем инициализированную обработку транспорта сообщений.
	ОбработкаТранспортаСообщенийОбмена = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена;
	ОбработкаТранспортаСообщенийОбмена.УзелИнформационнойБазы = СтруктураНастроекОбмена.УзелИнформационнойБазы;
	
	// Получаем сообщение обмена во временный каталог.
	Если Не ОбработкаТранспортаСообщенийОбмена.ПодключениеУстановлено()
		Или Не ОбработкаТранспортаСообщенийОбмена.ПолучитьСообщение() Тогда
		
		СтекОшибок.Добавить(ОбработкаТранспортаСообщенийОбмена.СтрокаСообщенияОбОшибкеЖР);
		
		Если Не ИспользоватьПсевдоним Тогда
			// Больше попыток поиска файла не будет, поэтому регистрируем все накопленные ошибки.
			Для Каждого ТекущаяОшибка Из СтекОшибок Цикл
				ЗаписьЖурналаРегистрацииОбменаДанными(ТекущаяОшибка, СтруктураНастроекОбмена, Истина);
			КонецЦикла;
		КонецЕсли;
		
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения;
		
	КонецЕсли;
	
	Если ИспользоватьПсевдоним
		И СтруктураНастроекОбмена.РезультатВыполненияОбмена <> Неопределено Тогда
		// Возможно, сообщение удастся получить если применить виртуальный код узла (псевдоним).
		
		Транслитерация = Неопределено;
		Если СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.FILE Тогда
			СтруктураНастроекОбмена.НастройкиТранспорта.Свойство("FILEТранслитерироватьИменаФайловСообщенийОбмена", Транслитерация);
		ИначеЕсли СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.EMAIL Тогда
			СтруктураНастроекОбмена.НастройкиТранспорта.Свойство("EMAILТранслитерироватьИменаФайловСообщенийОбмена", Транслитерация);
		ИначеЕсли СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.FTP Тогда
			СтруктураНастроекОбмена.НастройкиТранспорта.Свойство("FTPТранслитерироватьИменаФайловСообщенийОбмена", Транслитерация);
		КонецЕсли;
		Транслитерация = ?(Транслитерация = Неопределено, Ложь, Транслитерация);
		
		ШаблонИмениФайлаСтарый = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена.ШаблонИмениФайлаСообщения;
		СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена.ШаблонИмениФайлаСообщения = ШаблонИмениФайлаСообщения(
				СтруктураНастроекОбмена.ТекущийУзелПланаОбмена,
				СтруктураНастроекОбмена.УзелИнформационнойБазы,
				Ложь,
				Транслитерация, 
				Истина);
		Если ШаблонИмениФайлаСтарый <> СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена.ШаблонИмениФайлаСообщения Тогда
			// Попытка повторного выполнения транспорта с новым шаблоном.
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено;
			ВыполнитьТранспортСообщенияОбменаПолучение(СтруктураНастроекОбмена, Ложь, СтекОшибок);
		Иначе
			// Больше попыток поиска файла не будет, поэтому регистрируем все накопленные ошибки.
			Для Каждого ТекущаяОшибка Из СтекОшибок Цикл
				ЗаписьЖурналаРегистрацииОбменаДанными(ТекущаяОшибка, СтруктураНастроекОбмена, Истина);
			КонецЦикла;
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьТранспортСообщенияОбменаПослеОбработки(СтруктураНастроекОбмена)
	
	// Получаем инициализированную обработку транспорта сообщений.
	ОбработкаТранспортаСообщенийОбмена = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена;
	
	// Выполняем действия после отправки сообщения.
	ОбработкаТранспортаСообщенийОбмена.ВыполнитьДействияПослеОбработкиСообщения();
	
КонецПроцедуры

// Получает настройки прокси сервера.
//
Функция НастройкиПроксиСервера(ЗащищенноеСоединение)
	
	Прокси = Неопределено;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда
		МодульПолучениеФайловИзИнтернета = ОбщегоНазначения.ОбщийМодуль("ПолучениеФайловИзИнтернета");
		Протокол = ?(ЗащищенноеСоединение = Неопределено, "ftp", "ftps");
		Прокси = МодульПолучениеФайловИзИнтернета.ПолучитьПрокси(Протокол);
	КонецЕсли;
	
	Возврат Прокси;
	
КонецФункции
#КонецОбласти

#Область СервисПередачиФайлов

// Получение имени файла по его идентификатору из хранилища.
// Если файла с указанным идентификатором нет, то вызывается исключение.
// Если файл найден, то возвращается его имя, при этом удаляется информация об этом файле из хранилища.
//
// Параметры:
//  ИдентификаторФайла  - УникальныйИдентификатор - идентификатор получаемого файла.
//  ИмяФайла            - Строка - имя файла, из хранилища.
//
Процедура ПриПолученииФайлаИзХранилища(Знач ИдентификаторФайла, ИмяФайла)
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	СообщенияОбменаДанными.ИмяФайлаСообщения КАК ИмяФайла
	|ИЗ
	|	РегистрСведений.СообщенияОбменаДанными КАК СообщенияОбменаДанными
	|ГДЕ
	|	СообщенияОбменаДанными.ИдентификаторСообщения = &ИдентификаторСообщения";
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ИдентификаторСообщения", Строка(ИдентификаторФайла));
	Запрос.Текст = ТекстЗапроса;
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если РезультатЗапроса.Пустой() Тогда
		Описание = НСтр("ru = 'Файл с идентификатором %1 не обнаружен.'");
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Описание, Строка(ИдентификаторФайла));
	КонецЕсли;
	
	Выборка = РезультатЗапроса.Выбрать();
	Выборка.Следующий();
	ИмяФайла = Выборка.ИмяФайла;
	
	// Удаляем информацию о файле сообщения обмена из хранилища.
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("ИдентификаторСообщения", Строка(ИдентификаторФайла));
	РегистрыСведений.СообщенияОбменаДанными.УдалитьЗапись(СтруктураЗаписи);
	
КонецПроцедуры

// Помещение файла в хранилище.
//
Процедура ПриПомещенииФайлаВХранилище(Знач СтруктураЗаписи)
	
	РегистрыСведений.СообщенияОбменаДанными.ДобавитьЗапись(СтруктураЗаписи);
	
КонецПроцедуры

#КонецОбласти

#Область РегистрацияИзмененийНачальнойВыгрузкиДанных

// Выполняет регистрацию изменений для начальной выгрузки данных с учетом даты начала выгрузки и списка организаций.
// Процедура является универсальной и может быть использована для регистрации изменений данных по дате начала выгрузки
// и списку организаций для объектных типов данных и наборов записей регистров.
// Если список организаций не задан (Организации = Неопределено), то изменения регистрируются только по дате начала
// выгрузки.
// Регистрации подлежат данные для всех объектов метаданных, включенных в состав плана обмена.
// Если для объекта метаданных в составе плана обмена установлен признак авторегистрации
// или если признак авторегистрации не установлен и правила регистрации не заданы,
// то регистрация изменений будет выполнена безусловно для всех данных этого типа.
// Если для объекта метаданных заданы правила регистрации, то регистрация изменений будет выполнена 
// с учетом даты начала выгрузки и списка организаций.
// Для документов поддерживается регистрация изменений по дате начала выгрузки и по списку организаций.
// Для бизнес-процессов и для задач поддерживается регистрация изменений по дате начала выгрузки.
// Для наборов записей регистров поддерживается регистрация изменений по дате начала выгрузки и по списку организаций.
// Данная процедура может служить прототипом для разработки собственных процедур регистрации изменений
// для начальной выгрузки данных.
//
// Параметры:
//
//  Получатель - ПланОбменаСсылка - узел плана обмена,
//               для которого требуется выполнить регистрацию изменений данных.
//  ДатаНачалаВыгрузки - Дата - дата, относительно которой необходимо выполнить
//               регистрацию изменений данных для выгрузки. Изменения будут зарегистрированы для данных,
//               которые на оси времени располагаются после этой даты.
//  Организации - Массив
//              - Неопределено - список организаций, для которых необходимо выполнить регистрацию
//               изменений данных. Если параметр не задан, то организации не будут
//               учитываться при регистрации изменений.
//
Процедура ЗарегистрироватьДанныеПоДатеНачалаВыгрузкиИОрганизациям(Знач Получатель, ДатаНачалаВыгрузки,
	Организации = Неопределено,
	Данные = Неопределено) Экспорт
	
	ОтборПоОрганизациям = (Организации <> Неопределено);
	ОтборПоДатеНачалаВыгрузки = ЗначениеЗаполнено(ДатаНачалаВыгрузки);
	
	Если Не ОтборПоОрганизациям И Не ОтборПоДатеНачалаВыгрузки Тогда
		
		Если ТипЗнч(Данные) = Тип("Массив") Тогда
			
			Для Каждого ОбъектМетаданных Из Данные Цикл
				
				ПланыОбмена.ЗарегистрироватьИзменения(Получатель, ОбъектМетаданных);
				
			КонецЦикла;
			
		Иначе
			
			ПланыОбмена.ЗарегистрироватьИзменения(Получатель, Данные);
			
		КонецЕсли;
		
		Возврат;
	КонецЕсли;
	
	ОтборПоДатеНачалаВыгрузкиИОрганизациям = ОтборПоДатеНачалаВыгрузки И ОтборПоОрганизациям;
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Получатель);
	
	СоставПланаОбмена = Метаданные.ПланыОбмена[ИмяПланаОбмена].Состав;
	
	ИспользоватьФильтрПоМетаданным = (ТипЗнч(Данные) = Тип("Массив"));
	
	Для Каждого ЭлементСоставаПланаОбмена Из СоставПланаОбмена Цикл
		
		Если ИспользоватьФильтрПоМетаданным
			И Данные.Найти(ЭлементСоставаПланаОбмена.Метаданные) = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		ПолноеИмяОбъекта = ЭлементСоставаПланаОбмена.Метаданные.ПолноеИмя();
		
		Если ЭлементСоставаПланаОбмена.АвтоРегистрация = АвтоРегистрацияИзменений.Запретить
			И ОбменДаннымиПовтИсп.ПравилаРегистрацииОбъектаСуществуют(ИмяПланаОбмена, ПолноеИмяОбъекта) Тогда
			
			Если ОбщегоНазначения.ЭтоДокумент(ЭлементСоставаПланаОбмена.Метаданные) Тогда // Документы
				
				Если ОтборПоДатеНачалаВыгрузкиИОрганизациям
					// Регистрация по дате и организациям.
					И ЭлементСоставаПланаОбмена.Метаданные.Реквизиты.Найти("Организация") <> Неопределено Тогда
					
					Выборка = ВыборкаДокументовПоДатеНачалаВыгрузкиИОрганизациям(ПолноеИмяОбъекта, ДатаНачалаВыгрузки, Организации);
					
					Пока Выборка.Следующий() Цикл
						
						ПланыОбмена.ЗарегистрироватьИзменения(Получатель, Выборка.Ссылка);
						
					КонецЦикла;
					
					Продолжить;
					
				Иначе // Регистрация по дате
					
					Выборка = ВыборкаОбъектовПоДатеНачалаВыгрузки(ПолноеИмяОбъекта, ДатаНачалаВыгрузки);
					
					Пока Выборка.Следующий() Цикл
						
						ПланыОбмена.ЗарегистрироватьИзменения(Получатель, Выборка.Ссылка);
						
					КонецЦикла;
					
					Продолжить;
					
				КонецЕсли;
				
			ИначеЕсли ОбщегоНазначения.ЭтоБизнесПроцесс(ЭлементСоставаПланаОбмена.Метаданные)
				ИЛИ ОбщегоНазначения.ЭтоЗадача(ЭлементСоставаПланаОбмена.Метаданные) Тогда // Бизнес-процессы и Задачи
				
				// Регистрация по дате
				Выборка = ВыборкаОбъектовПоДатеНачалаВыгрузки(ПолноеИмяОбъекта, ДатаНачалаВыгрузки);
				
				Пока Выборка.Следующий() Цикл
					
					ПланыОбмена.ЗарегистрироватьИзменения(Получатель, Выборка.Ссылка);
					
				КонецЦикла;
				
				Продолжить;
				
			ИначеЕсли ОбщегоНазначения.ЭтоРегистр(ЭлементСоставаПланаОбмена.Метаданные) Тогда // Регистры
				
				// Регистры сведений (независимые).
				Если ОбщегоНазначения.ЭтоРегистрСведений(ЭлементСоставаПланаОбмена.Метаданные)
					И ЭлементСоставаПланаОбмена.Метаданные.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.Независимый Тогда
					
					ОсновнойОтбор = ОсновнойОтборРегистраСведений(ЭлементСоставаПланаОбмена.Метаданные);
					
					ОтборПоПериоду     = (ОсновнойОтбор.Найти("Период") <> Неопределено);
					ОтборПоОрганизации = (ОсновнойОтбор.Найти("Организация") <> Неопределено);
					
					// Регистрация по дате и организациям.
					Если ОтборПоДатеНачалаВыгрузкиИОрганизациям И ОтборПоПериоду И ОтборПоОрганизации Тогда
						
						Выборка = ВыборкаЗначенийОсновногоОтбораРегистраСведенийПоДатеНачалаВыгрузкиИОрганизациям(ОсновнойОтбор, ПолноеИмяОбъекта, ДатаНачалаВыгрузки, Организации);
						
					ИначеЕсли ОтборПоДатеНачалаВыгрузки И ОтборПоПериоду Тогда // Регистрация по дате
						
						Выборка = ВыборкаЗначенийОсновногоОтбораРегистраСведенийПоДатеНачалаВыгрузки(ОсновнойОтбор, ПолноеИмяОбъекта, ДатаНачалаВыгрузки);
						
					ИначеЕсли ОтборПоОрганизациям И ОтборПоОрганизации Тогда // Регистрация по организациям.
						
						Выборка = ВыборкаЗначенийОсновногоОтбораРегистраСведенийПоОрганизациям(ОсновнойОтбор, ПолноеИмяОбъекта, Организации);
						
					Иначе
						
						Выборка = Неопределено;
						
					КонецЕсли;
					
					Если Выборка <> Неопределено Тогда
						
						НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяОбъекта).СоздатьНаборЗаписей();
						
						Пока Выборка.Следующий() Цикл
							
							Для Каждого ИмяИзмерения Из ОсновнойОтбор Цикл
								
								НаборЗаписей.Отбор[ИмяИзмерения].Значение = Выборка[ИмяИзмерения];
								НаборЗаписей.Отбор[ИмяИзмерения].Использование = Истина;
								
							КонецЦикла;
							
							ПланыОбмена.ЗарегистрироватьИзменения(Получатель, НаборЗаписей);
							
						КонецЦикла;
						
						Продолжить;
						
					КонецЕсли;
					
				Иначе // Регистры (прочие)
					ЕстьПериодВРегистре = ОбщегоНазначения.ЭтоРегистрБухгалтерии(ЭлементСоставаПланаОбмена.Метаданные)
							ИЛИ ОбщегоНазначения.ЭтоРегистрНакопления(ЭлементСоставаПланаОбмена.Метаданные)
							ИЛИ (ОбщегоНазначения.ЭтоРегистрСведений(ЭлементСоставаПланаОбмена.Метаданные)
								И ЭлементСоставаПланаОбмена.Метаданные.ПериодичностьРегистраСведений 
									<> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический);
					Если ОтборПоДатеНачалаВыгрузкиИОрганизациям
						И ЕстьПериодВРегистре
						// Регистрация по дате и организациям.
						И ЭлементСоставаПланаОбмена.Метаданные.Измерения.Найти("Организация") <> Неопределено Тогда
						
						Выборка = ВыборкаРегистраторовНаборовЗаписейПоДатеНачалаВыгрузкиИОрганизациям(ПолноеИмяОбъекта, ДатаНачалаВыгрузки, Организации);
						
						НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяОбъекта).СоздатьНаборЗаписей();
						
						Пока Выборка.Следующий() Цикл
							
							НаборЗаписей.Отбор.Регистратор.Значение = Выборка.Регистратор;
							НаборЗаписей.Отбор.Регистратор.Использование = Истина;
							
							ПланыОбмена.ЗарегистрироватьИзменения(Получатель, НаборЗаписей);
							
						КонецЦикла;
						
						Продолжить;
						
					// Регистрация по дате
					ИначеЕсли ЕстьПериодВРегистре Тогда
						
						Выборка = ВыборкаРегистраторовНаборовЗаписейПоДатеНачалаВыгрузки(ПолноеИмяОбъекта, ДатаНачалаВыгрузки);
						
						НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяОбъекта).СоздатьНаборЗаписей();
						
						Пока Выборка.Следующий() Цикл
							
							НаборЗаписей.Отбор.Регистратор.Значение = Выборка.Регистратор;
							НаборЗаписей.Отбор.Регистратор.Использование = Истина;
							
							ПланыОбмена.ЗарегистрироватьИзменения(Получатель, НаборЗаписей);
							
						КонецЦикла;
						
						Продолжить;
						
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
		
		ПланыОбмена.ЗарегистрироватьИзменения(Получатель, ЭлементСоставаПланаОбмена.Метаданные);
		
	КонецЦикла;
	
КонецПроцедуры

Функция ВыборкаДокументовПоДатеНачалаВыгрузкиИОрганизациям(ПолноеИмяОбъекта, ДатаНачалаВыгрузки, Организации)
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	Таблица.Ссылка КАК Ссылка
	|ИЗ
	|	&ПолноеИмяОбъекта КАК Таблица
	|ГДЕ
	|	Таблица.Организация В(&Организации)
	|	И Таблица.Дата >= &ДатаНачалаВыгрузки";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъекта", ПолноеИмяОбъекта);
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ДатаНачалаВыгрузки", ДатаНачалаВыгрузки);
	Запрос.УстановитьПараметр("Организации", Организации);
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос.Выполнить().Выбрать();
КонецФункции

Функция ВыборкаОбъектовПоДатеНачалаВыгрузки(ПолноеИмяОбъекта, ДатаНачалаВыгрузки)
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	Таблица.Ссылка КАК Ссылка
	|ИЗ
	|	&ПолноеИмяОбъекта КАК Таблица
	|ГДЕ
	|	Таблица.Дата >= &ДатаНачалаВыгрузки";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъекта", ПолноеИмяОбъекта);
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ДатаНачалаВыгрузки", ДатаНачалаВыгрузки);
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос.Выполнить().Выбрать();
КонецФункции

Функция ВыборкаРегистраторовНаборовЗаписейПоДатеНачалаВыгрузкиИОрганизациям(ПолноеИмяОбъекта, ДатаНачалаВыгрузки, Организации)
	
	ТекстЗапроса =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ТаблицаРегистра.Регистратор КАК Регистратор
	|ИЗ
	|	&ПолноеИмяОбъекта КАК ТаблицаРегистра
	|ГДЕ
	|	ТаблицаРегистра.Организация В(&Организации)
	|	И ТаблицаРегистра.Период >= &ДатаНачалаВыгрузки";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъекта", ПолноеИмяОбъекта);
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ДатаНачалаВыгрузки", ДатаНачалаВыгрузки);
	Запрос.УстановитьПараметр("Организации", Организации);
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос.Выполнить().Выбрать();
КонецФункции

Функция ВыборкаРегистраторовНаборовЗаписейПоДатеНачалаВыгрузки(ПолноеИмяОбъекта, ДатаНачалаВыгрузки)
	
	ТекстЗапроса =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ТаблицаРегистра.Регистратор КАК Регистратор
	|ИЗ
	|	&ПолноеИмяОбъекта КАК ТаблицаРегистра
	|ГДЕ
	|	ТаблицаРегистра.Период >= &ДатаНачалаВыгрузки";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъекта", ПолноеИмяОбъекта);
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ДатаНачалаВыгрузки", ДатаНачалаВыгрузки);
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос.Выполнить().Выбрать();
КонецФункции

Функция ВыборкаЗначенийОсновногоОтбораРегистраСведенийПоДатеНачалаВыгрузкиИОрганизациям(ОсновнойОтбор,
	ПолноеИмяОбъекта,
	ДатаНачалаВыгрузки,
	Организации)
	
	ТекстЗапроса =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	&Измерения
	|ИЗ
	|	&ПолноеИмяОбъекта КАК ТаблицаРегистра
	|ГДЕ
	|	ТаблицаРегистра.Организация В(&Организации)
	|	И ТаблицаРегистра.Период >= &ДатаНачалаВыгрузки";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъекта", ПолноеИмяОбъекта);
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Измерения", СтрСоединить(ОсновнойОтбор, ","));
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ДатаНачалаВыгрузки", ДатаНачалаВыгрузки);
	Запрос.УстановитьПараметр("Организации", Организации);
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос.Выполнить().Выбрать();
КонецФункции

Функция ВыборкаЗначенийОсновногоОтбораРегистраСведенийПоДатеНачалаВыгрузки(ОсновнойОтбор, ПолноеИмяОбъекта, ДатаНачалаВыгрузки)
	
	ТекстЗапроса =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	&Измерения
	|ИЗ
	|	&ПолноеИмяОбъекта КАК ТаблицаРегистра
	|ГДЕ
	|	ТаблицаРегистра.Период >= &ДатаНачалаВыгрузки";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъекта", ПолноеИмяОбъекта);
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Измерения", СтрСоединить(ОсновнойОтбор, ","));
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ДатаНачалаВыгрузки", ДатаНачалаВыгрузки);
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос.Выполнить().Выбрать();
КонецФункции

Функция ВыборкаЗначенийОсновногоОтбораРегистраСведенийПоОрганизациям(ОсновнойОтбор, ПолноеИмяОбъекта, Организации)
	
	ТекстЗапроса =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	&Измерения
	|ИЗ
	|	&ПолноеИмяОбъекта КАК ТаблицаРегистра
	|ГДЕ
	|	ТаблицаРегистра.Организация В(&Организации)";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъекта", ПолноеИмяОбъекта);
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Измерения", СтрСоединить(ОсновнойОтбор, ","));
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Организации", Организации);
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос.Выполнить().Выбрать();
КонецФункции

Функция ОсновнойОтборРегистраСведений(ОбъектМетаданных)
	
	Результат = Новый Массив;
	
	Если ОбъектМетаданных.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический
		И ОбъектМетаданных.ОсновнойОтборПоПериоду Тогда
		
		Результат.Добавить("Период");
		
	КонецЕсли;
	
	Для Каждого Измерение Из ОбъектМетаданных.Измерения Цикл
		
		Если Измерение.ОсновнойОтбор Тогда
			
			Результат.Добавить(Измерение.Имя);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

#КонецОбласти

#Область ОберткиДляРаботыСПрограммнымИнтерфейсомМенеджераПланаОбмена

Функция ОбщиеДанныеУзлов(Знач ИмяПланаОбмена, Знач ВерсияКорреспондента, Знач ИдентификаторНастройки) Экспорт
	
	Если ПустаяСтрока(ВерсияКорреспондента) Тогда
		ВерсияКорреспондента = "0.0.0.0";
	КонецЕсли;
	
	ОписаниеВариантаНастройки = ОбменДаннымиПовтИсп.ОписаниеВариантаНастройки(ИмяПланаОбмена, 
								ИдентификаторНастройки, ВерсияКорреспондента);
	Результат = ОписаниеВариантаНастройки.ОбщиеДанныеУзлов;
	
	Возврат СтрЗаменить(Результат, " ", "");
	
КонецФункции

Процедура ПриПодключенииККорреспонденту(Знач ИмяПланаОбмена, Знач ВерсияКорреспондента) Экспорт
	Если НЕ ЕстьАлгоритмМенеджераПланаОбмена("ПриПодключенииККорреспонденту", ИмяПланаОбмена) Тогда
		Возврат;
	ИначеЕсли ПустаяСтрока(ВерсияКорреспондента) Тогда
		ВерсияКорреспондента = "0.0.0.0";
	КонецЕсли;
	
	ПланыОбмена[ИмяПланаОбмена].ПриПодключенииККорреспонденту(ВерсияКорреспондента);
	
КонецПроцедуры

// Заполняет настройки для плана обмена, которые далее используются подсистемой обмена данными.
// Параметры:
//   ИмяПланаОбмена              - Строка - имя плана обмена.
//   ВерсияКорреспондента        - Строка - версия конфигурации-корреспондента.
//   ИмяКорреспондента           - Строка - имя конфигурации корреспондента.
//   КорреспондентВМоделиСервиса - Булево, Неопределено - признак того, что корреспондент находится в модели сервиса.
// Возвращаемое значение:
//   см. НастройкиПланаОбменаПоУмолчанию.
//
Функция НастройкиПланаОбмена(ИмяПланаОбмена, ВерсияКорреспондента, ИмяКорреспондента, КорреспондентВМоделиСервиса) Экспорт
	НастройкиПланаОбмена = НастройкиПланаОбменаПоУмолчанию(ИмяПланаОбмена);
	УстановитьПривилегированныйРежим(Истина);
	ПланыОбмена[ИмяПланаОбмена].ПриПолученииНастроек(НастройкиПланаОбмена);
	ЕстьОбработчикПолученияВариантов = НастройкиПланаОбмена.Алгоритмы.ПриПолученииВариантовНастроекОбмена;
	// Требуется инициализация вариантов.
	Если ЕстьОбработчикПолученияВариантов Тогда
		ПараметрыОтбора = ПараметрыКонтекстаПолученияВариантовНастроек(ИмяКорреспондента, ВерсияКорреспондента, КорреспондентВМоделиСервиса);
		ПланыОбмена[ИмяПланаОбмена].ПриПолученииВариантовНастроекОбмена(НастройкиПланаОбмена.ВариантыНастроекОбмена, ПараметрыОтбора);
	Иначе
		// Варианты не используются - следует добавить служебный вариант.
		ВариантНастройки = НастройкиПланаОбмена.ВариантыНастроекОбмена.Добавить();
		ВариантНастройки.ИдентификаторНастройки = "";
		ВариантНастройки.КорреспондентВМоделиСервиса = ОбщегоНазначения.РазделениеВключено() 
			И НастройкиПланаОбмена.ПланОбменаИспользуетсяВМоделиСервиса;
		ВариантНастройки.КорреспондентВЛокальномРежиме = Истина;
	КонецЕсли;
	УстановитьПривилегированныйРежим(Ложь);

	Возврат НастройкиПланаОбмена;
КонецФункции

// Заполняет настройки, относящиеся к варианту настройки обмена, которые далее используются подсистемой обмена данными.
//
// Параметры:
//   ИмяПланаОбмена         - Строка - имя плана обмена.
//   ИдентификаторНастройки - Строка - идентификатор варианта настройки обмена.
//   ВерсияКорреспондента   - Строка - версия конфигурации-корреспондента.
//   ИмяКорреспондента      - Строка - имя конфигурации корреспондента.
//
// Возвращаемое значение:
//   см. ОписаниеВариантаНастройкиОбменаПоУмолчанию
//
Функция ОписаниеВариантаНастройки(ИмяПланаОбмена, ИдентификаторНастройки, 
								ВерсияКорреспондента, ИмяКорреспондента) Экспорт
	ОписаниеВариантаНастройки = ОписаниеВариантаНастройкиОбменаПоУмолчанию(ИмяПланаОбмена);
	ЕстьОбработчикОписанияВарианта = ЕстьАлгоритмМенеджераПланаОбмена("ПриПолученииОписанияВариантаНастройки", ИмяПланаОбмена);
	Если ЕстьОбработчикОписанияВарианта Тогда
		ПараметрыВарианта = ПараметрыКонтекстаПолученияОписанияВариантаНастройки(ИмяКорреспондента, ВерсияКорреспондента);
		ПланыОбмена[ИмяПланаОбмена].ПриПолученииОписанияВариантаНастройки(
							ОписаниеВариантаНастройки, ИдентификаторНастройки, ПараметрыВарианта);
	КонецЕсли;
	Возврат ОписаниеВариантаНастройки;
КонецФункции

#КонецОбласти

#Область РаботаСПаролямиСинхронизацииДанных

// Возвращает значения пароля синхронизации данных для заданного узла.
// Если пароля нет, то возвращается Неопределено.
//
// Возвращаемое значение:
//  Строка, Неопределено - значения пароля синхронизации данных.
//
Функция ПарольСинхронизацииДанных(Знач УзелИнформационнойБазы) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат ПараметрыСеанса.ПаролиСинхронизацииДанных.Получить(УзелИнформационнойБазы);
КонецФункции

// Возвращает признак того, что пароль синхронизации данных был задан пользователем.
//
Функция ПарольСинхронизацииДанныхЗадан(Знач УзелИнформационнойБазы) Экспорт
	
	Возврат ПарольСинхронизацииДанных(УзелИнформационнойБазы) <> Неопределено;
	
КонецФункции

#КонецОбласти

#Область КонтрольНеразделенныхДанных

// Вызывается при проверке доступности неразделенных данных для записи.
//
Процедура ВыполнитьКонтрольЗаписиНеразделенныхДанных(Знач Данные) Экспорт
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных()
		И Не ЭтоРазделенныйОбъект(Данные) Тогда
		
		ТекстИсключения = НСтр("ru = 'Недостаточно прав для выполнения действия.'", ОбщегоНазначения.КодОсновногоЯзыка());
		
		ЗаписьЖурналаРегистрации(
			ТекстИсключения,
			УровеньЖурналаРегистрации.Ошибка,
			Данные.Метаданные());
		
		ВызватьИсключение ТекстИсключения;
	КонецЕсли;
	
КонецПроцедуры

Функция ЭтоРазделенныйОбъект(Знач Объект)
	
	ПолноеИмя = Объект.Метаданные().ПолноеИмя();
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(ПолноеИмя);
	Иначе
		ЭтоРазделенныйОбъектМетаданных = Ложь;
	КонецЕсли;
	
	Возврат ЭтоРазделенныйОбъектМетаданных;
	
КонецФункции

#КонецОбласти

#Область РаботаСМониторомОбменаДанными

// Возвращает структуру с данными последнего обмена для заданного узла информационной базы.
//
// Параметры:
//  Нет.
// 
// Возвращаемое значение:
//  СостоянияОбменовДанными - Структура - структура с данными последнего обмена для заданного узла информационной базы.
//
Функция СостоянияОбменовДаннымиДляУзлаИнформационнойБазы(Знач УзелИнформационнойБазы) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	// Возвращаемое значение функции.
	СостоянияОбменовДанными = Новый Структура;
	СостоянияОбменовДанными.Вставить("УзелИнформационнойБазы");
	СостоянияОбменовДанными.Вставить("РезультатЗагрузкиДанных", "Неопределено");
	СостоянияОбменовДанными.Вставить("РезультатВыгрузкиДанных", "Неопределено");
	
	ТекстЗапроса = "
	|// {ЗАПРОС №0}
	|////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ВЫБОР
	|	КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Выполнено)
	|	ТОГДА ""Успех""
	|	
	|	КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями)
	|	ТОГДА ""ВыполненоСПредупреждениями""
	|	
	|	КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Предупреждение_СообщениеОбменаБылоРанееПринято)
	|	ТОГДА ""Предупреждение_СообщениеОбменаБылоРанееПринято""
	|	
	|	КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения)
	|	ТОГДА ""Ошибка_ТранспортСообщения""
	|	
	|	ИНАЧЕ ""Ошибка""
	|	
	|	КОНЕЦ КАК РезультатВыполненияОбмена
	|ИЗ
	|	РегистрСведений.СостоянияОбменовДанными КАК СостоянияОбменовДанными
	|ГДЕ
	|	  СостоянияОбменовДанными.УзелИнформационнойБазы = &УзелИнформационнойБазы
	|	И СостоянияОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
	|;
	|// {ЗАПРОС №1}
	|////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ВЫБОР
	|	КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Выполнено)
	|	ТОГДА ""Успех""
	|	
	|	КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями)
	|	ТОГДА ""ВыполненоСПредупреждениями""
	|	
	|	КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Предупреждение_СообщениеОбменаБылоРанееПринято)
	|	ТОГДА ""Предупреждение_СообщениеОбменаБылоРанееПринято""
	|	
	|	КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения)
	|	ТОГДА ""Ошибка_ТранспортСообщения""
	|	
	|	ИНАЧЕ ""Ошибка""
	|	КОНЕЦ КАК РезультатВыполненияОбмена
	|	
	|ИЗ
	|	РегистрСведений.СостоянияОбменовДанными КАК СостоянияОбменовДанными
	|ГДЕ
	|	  СостоянияОбменовДанными.УзелИнформационнойБазы = &УзелИнформационнойБазы
	|	И СостоянияОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)
	|;
	|";
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		
		МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
		МодульОбменДаннымиВМоделиСервиса.АдаптироватьТекстЗапросаОРезультатахОбменаВСервисе(ТекстЗапроса);
		
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("УзелИнформационнойБазы", УзелИнформационнойБазы);
	
	МассивРезультатовЗапроса = Запрос.ВыполнитьПакет(); // Массив из РезультатЗапроса
	
	ВыборкаРезультатовЗагрузкиДанных = МассивРезультатовЗапроса[0].Выбрать();
	ВыборкаРезультатовВыгрузкиДанных = МассивРезультатовЗапроса[1].Выбрать();
	
	Если ВыборкаРезультатовЗагрузкиДанных.Следующий() Тогда
		
		СостоянияОбменовДанными.РезультатЗагрузкиДанных = ВыборкаРезультатовЗагрузкиДанных.РезультатВыполненияОбмена;
		
	КонецЕсли;
	
	Если ВыборкаРезультатовВыгрузкиДанных.Следующий() Тогда
		
		СостоянияОбменовДанными.РезультатВыгрузкиДанных = ВыборкаРезультатовВыгрузкиДанных.РезультатВыполненияОбмена;
		
	КонецЕсли;
	
	СостоянияОбменовДанными.УзелИнформационнойБазы = УзелИнформационнойБазы;
	
	Возврат СостоянияОбменовДанными;
КонецФункции

// Возвращает структуру с данными последнего обмена для заданного узла информационной базы и действия при обмене.
//
// Параметры:
//  Нет.
// 
// Возвращаемое значение:
//  СостоянияОбменовДанными - Структура - структура с данными последнего обмена для заданного узла информационной базы.
//
Функция СостоянияОбменовДанными(Знач УзелИнформационнойБазы, ДействиеПриОбмене) Экспорт
	
	// Возвращаемое значение функции.
	СостоянияОбменовДанными = Новый Структура;
	СостоянияОбменовДанными.Вставить("ДатаНачала",    Дата('00010101'));
	СостоянияОбменовДанными.Вставить("ДатаОкончания", Дата('00010101'));
	
	ТекстЗапроса = "
	|ВЫБРАТЬ
	|	ДатаНачала,
	|	ДатаОкончания
	|ИЗ
	|	РегистрСведений.СостоянияОбменовДанными КАК СостоянияОбменовДанными
	|ГДЕ
	|	  СостоянияОбменовДанными.УзелИнформационнойБазы = &УзелИнформационнойБазы
	|	И СостоянияОбменовДанными.ДействиеПриОбмене      = &ДействиеПриОбмене
	|";
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		
		МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
		МодульОбменДаннымиВМоделиСервиса.АдаптироватьТекстЗапросаОРезультатахОбменаВСервисе(ТекстЗапроса);
		
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("УзелИнформационнойБазы", УзелИнформационнойБазы);
	Запрос.УстановитьПараметр("ДействиеПриОбмене",      ДействиеПриОбмене);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Если Выборка.Следующий() Тогда
		
		ЗаполнитьЗначенияСвойств(СостоянияОбменовДанными, Выборка);
		
	КонецЕсли;
	
	Возврат СостоянияОбменовДанными;
	
КонецФункции

#КонецОбласти

#Область ИнициализацияСеанса

// Получает массив всех планов обмена по которым выполняется обмен данными.
// Наличие обмена с каким либо планом обмена определяется по наличию у этого плана обмена узлов кроме предопределенного.
//
// Параметры:
//  Нет.
// 
// Возвращаемое значение:
//  МассивПлановОбмена - Массив - массив строк (имен) всех планов обмена по которым выполняется обмен данными.
//
Функция ПолучитьИспользуемыеПланыОбмена() Экспорт
	
	// возвращаемое значение
	МассивПлановОбмена = Новый Массив;
	
	Для Каждого ИмяПланаОбмена Из ОбменДаннымиПовтИсп.ПланыОбменаБСП() Цикл
		
		Если Не ПланОбменаНеСодержитУзлов(ИмяПланаОбмена) Тогда
			
			МассивПлановОбмена.Добавить(ИмяПланаОбмена);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат МассивПлановОбмена;
	
КонецФункции

// Получает таблицу правил регистрации объектов из информационной базы.
//
// Параметры:
//  Нет.
// 
// Возвращаемое значение:
//  ПравилаРегистрацииОбъектов - ТаблицаЗначений - таблица общих правил регистрации объектов для МРО.
// 
Функция ПолучитьПравилаРегистрацииОбъектов() Экспорт
	
	// Возвращаемое значение функции.
	ПравилаРегистрацииОбъектов = ИнициализацияТаблицыПравилРегистрацииОбъектов();
	
	ТекстЗапроса = 
		"ВЫБРАТЬ
		|	Правила.ПравилаЗачитанные КАК ПравилаЗачитанные,
		|	Правила.ИмяПланаОбмена КАК ИмяПланаОбмена,
		|	Правила.ИсточникПравил КАК ИсточникПравил,
		|	Правила.ИмяМенеджераРегистрации КАК ИмяМенеджераРегистрации
		|ИЗ
		|	РегистрСведений.ПравилаДляОбменаДанными КАК Правила
		|ГДЕ
		|	(Правила.ВидПравил = ЗНАЧЕНИЕ(Перечисление.ВидыПравилДляОбменаДанными.ПравилаРегистрацииОбъектов)
		|				И Правила.ПравилаЗагружены
		|			ИЛИ Правила.ИсточникПравил В (&ИсточникиПравилМенеджеры))";
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	
	ИсточникиПравилМенеджеры = Новый Массив;
	ИсточникиПравилМенеджеры.Добавить(Перечисления.ИсточникиПравилДляОбменаДанными.МенеджерТиповой);
	ИсточникиПравилМенеджеры.Добавить(Перечисления.ИсточникиПравилДляОбменаДанными.МенеджерПользовательский);
	
	Запрос.УстановитьПараметр("ИсточникиПравилМенеджеры", ИсточникиПравилМенеджеры);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		Если Выборка.ИсточникПравил = Перечисления.ИсточникиПравилДляОбменаДанными.МенеджерТиповой
			Или Выборка.ИсточникПравил = Перечисления.ИсточникиПравилДляОбменаДанными.МенеджерПользовательский Тогда
			
			Если Выборка.ИсточникПравил = Перечисления.ИсточникиПравилДляОбменаДанными.МенеджерТиповой Тогда 
				ИмяМенеджераРегистрации = ОбменДаннымиПовтИсп.ИмяМенеджераРегистрации(Выборка.ИмяПланаОбмена);
			Иначе
				ИмяМенеджераРегистрации = Выборка.ИмяМенеджераРегистрации;	
			КонецЕсли;
			
			Менеджер = ОбщегоНазначения.ОбщийМодуль(ИмяМенеджераРегистрации);
			Менеджер.ИнициализацияПравилРегистрации(ПравилаРегистрацииОбъектов, ИмяМенеджераРегистрации);
			
		Иначе
			
			ПравилаЗачитанные = Выборка.ПравилаЗачитанные.Получить();
			Если ПравилаЗачитанные = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			ЗаполнитьЗначенияСвойствДляТаблицыЗначенийПРО(ПравилаРегистрацииОбъектов, ПравилаЗачитанные);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат ПравилаРегистрацииОбъектов;
	
КонецФункции

Функция ИнициализацияТаблицыПравилРегистрацииОбъектов() Экспорт
	
	// Возвращаемое значение функции.
	Правила = Новый ТаблицаЗначений;
	
	Колонки = Правила.Колонки;
	
	Колонки.Добавить("ОбъектМетаданныхИмя", Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("Идентификатор",       Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("ИмяПланаОбмена",      Новый ОписаниеТипов("Строка"));
	
	Колонки.Добавить("ИмяРеквизитаФлага", Новый ОписаниеТипов("Строка"));
	
	Колонки.Добавить("ТекстЗапроса",    Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("СвойстваОбъекта", Новый ОписаниеТипов("Структура"));
	
	Колонки.Добавить("СвойстваОбъектаСтрокой", Новый ОписаниеТипов("Строка"));
	
	// Признаки того, что правила пустые.
	Колонки.Добавить("ПравилоПоСвойствамОбъектаПустое", Новый ОписаниеТипов("Булево"));
	
	// обработчики событий
	Колонки.Добавить("ПередОбработкой",            Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("ПриОбработке",               Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("ПриОбработкеДополнительный", Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("ПослеОбработки",             Новый ОписаниеТипов("Строка"));
	
	Колонки.Добавить("ЕстьОбработчикПередОбработкой",            Новый ОписаниеТипов("Булево"));
	Колонки.Добавить("ЕстьОбработчикПриОбработке",               Новый ОписаниеТипов("Булево"));
	Колонки.Добавить("ЕстьОбработчикПриОбработкеДополнительный", Новый ОписаниеТипов("Булево"));
	Колонки.Добавить("ЕстьОбработчикПослеОбработки",             Новый ОписаниеТипов("Булево"));
	Колонки.Добавить("ПакетноеВыполнениеОбработчиков",           Новый ОписаниеТипов("Булево"));
	
	Колонки.Добавить("ОтборПоСвойствамОбъекта", Новый ОписаниеТипов("ДеревоЗначений"));
	
	// Поле для оперативного хранения данных из объекта или ссылки.
	Колонки.Добавить("ОтборПоСвойствам", Новый ОписаниеТипов("ДеревоЗначений"));
	
	// добавляем индекс
	Правила.Индексы.Добавить("ИмяПланаОбмена, ОбъектМетаданныхИмя");
	
	Колонки.Добавить("ОтборПоСвойствамПланаОбмена", Новый ОписаниеТипов("ДеревоЗначений"));
	Колонки.Добавить("ИмяМенеджераРегистрации");
	
	Возврат Правила;
	
КонецФункции

Функция ПланОбменаНеСодержитУзлов(Знач ИмяПланаОбмена)
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	ИСТИНА
	|ИЗ
	|	#ИмяТаблицыПланаОбмена КАК ПланОбмена
	|ГДЕ
	|	НЕ ПланОбмена.ЭтотУзел");
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ИмяТаблицыПланаОбмена", "ПланОбмена." + ИмяПланаОбмена);
	
	Возврат Запрос.Выполнить().Пустой();
	
КонецФункции

Процедура ЗаполнитьЗначенияСвойствДляТаблицыЗначенийПРО(ТаблицаПриемник, ТаблицаИсточник)
	
	Для Каждого СтрокаИсточника Из ТаблицаИсточник Цикл
		
		ЗаполнитьЗначенияСвойств(ТаблицаПриемник.Добавить(), СтрокаИсточника);
		
	КонецЦикла;
	
КонецПроцедуры

Функция ОписаниеПравилСинхронизацииДанных(Знач УзелИнформационнойБазы) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ВерсияКорреспондента = ВерсияКорреспондента(УзелИнформационнойБазы);
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
	
	Настройка = ЗначенияНастроекОтборовНаУзле(УзелИнформационнойБазы, ВерсияКорреспондента);
	
	ОписаниеПравилСинхронизацииДанных = ОписаниеОграниченийПередачиДанных(
		ИмяПланаОбмена, Настройка, ВерсияКорреспондента,СохраненныйВариантНастройкиУзлаПланаОбмена(УзелИнформационнойБазы));
	
	УстановитьПривилегированныйРежим(Ложь);
	
	Возврат ОписаниеПравилСинхронизацииДанных;
	
КонецФункции

Функция ЗначенияНастроекОтборовНаУзле(Знач УзелИнформационнойБазы, Знач ВерсияКорреспондента)
	
	Результат = Новый Структура;
	
	УзелИнформационнойБазыОбъект = УзелИнформационнойБазы.ПолучитьОбъект();
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
	
	НастройкаОтборовНаУзле = НастройкаОтборовНаУзле(ИмяПланаОбмена,
		ВерсияКорреспондента, СохраненныйВариантНастройкиУзлаПланаОбмена(УзелИнформационнойБазы));
	
	Для Каждого Настройка Из НастройкаОтборовНаУзле Цикл
		
		Если ТипЗнч(Настройка.Значение) = Тип("Структура") Тогда
			
			ТабличнаяЧасть = Новый Структура;
			
			Для Каждого Колонка Из Настройка.Значение Цикл
				
				ТабличнаяЧасть.Вставить(Колонка.Ключ, УзелИнформационнойБазыОбъект[Настройка.Ключ].ВыгрузитьКолонку(Колонка.Ключ));
				
			КонецЦикла;
			
			Результат.Вставить(Настройка.Ключ, ТабличнаяЧасть);
			
		Иначе
			
			Результат.Вставить(Настройка.Ключ, УзелИнформационнойБазыОбъект[Настройка.Ключ]);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Процедура УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском(Знач Свойство, Знач ВключитьРежим) Экспорт
	
	// Перед вызовом требуется установить привилегированный режим.
	
	Если ЭтоПодчиненныйУзелРИБ() Тогда
		
		НоваяСтруктура = Новый Структура(ПараметрыСеанса.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском);
		Если ВключитьРежим Тогда
			Если НЕ НоваяСтруктура.Свойство(Свойство) Тогда
				НоваяСтруктура.Вставить(Свойство);
			КонецЕсли;
		Иначе
			Если НоваяСтруктура.Свойство(Свойство) Тогда
				НоваяСтруктура.Удалить(Свойство);
			КонецЕсли;
		КонецЕсли;
		
		ПараметрыСеанса.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском =
			Новый ФиксированнаяСтруктура(НоваяСтруктура);
	Иначе
		
		ПараметрыСеанса.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском = Новый ФиксированнаяСтруктура;
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область РаботаСМониторомПроблемОбменаДанными

Функция КоличествоПроблемОбменаДанными(УзлыОбмена = Неопределено)
	
	ПараметрыПоискаПроблем = РегистрыСведений.РезультатыОбменаДанными.ПараметрыПоискаПроблем();
	ПараметрыПоискаПроблем.УзлыПланаОбмена = УзлыОбмена;
	
	ТипыПроблем = Новый Массив;
	ТипыПроблем.Добавить(Перечисления.ТипыПроблемОбменаДанными.НезаполненныеРеквизиты);
	ТипыПроблем.Добавить(Перечисления.ТипыПроблемОбменаДанными.НепроведенныйДокумент);
	ТипыПроблем.Добавить(Перечисления.ТипыПроблемОбменаДанными.ОшибкаПроверкиСконвертированногоОбъекта);
	
	ПараметрыПоискаПроблем.ТипПроблемы = ТипыПроблем;
	
	Возврат РегистрыСведений.РезультатыОбменаДанными.КоличествоПроблем(ПараметрыПоискаПроблем);
	
КонецФункции

Функция КоличествоПроблемВерсионирования(УзлыОбмена = Неопределено, Знач ПараметрыЗапроса = Неопределено) Экспорт
	
	Если ПараметрыЗапроса = Неопределено Тогда
		ПараметрыЗапроса = ПараметрыЗапросаКоличествоПроблемВерсионирования();
	КонецЕсли;
	
	ИспользуетсяВерсионирование = ОбменДаннымиПовтИсп.ИспользуетсяВерсионирование(, Истина);
	
	Если ИспользуетсяВерсионирование Тогда
		МодульВерсионированиеОбъектов = ОбщегоНазначения.ОбщийМодуль("ВерсионированиеОбъектов");
		Возврат МодульВерсионированиеОбъектов.КоличествоКоллизийИлиНепринятых(
			УзлыОбмена,
			ПараметрыЗапроса.ЭтоКоличествоКоллизий,
			ПараметрыЗапроса.УчитыватьПроигнорированные,
			ПараметрыЗапроса.Период,
			ПараметрыЗапроса.СтрокаПоиска);
	КонецЕсли;
		
	Возврат 0;
	
КонецФункции

Функция ПараметрыЗапросаКоличествоПроблемВерсионирования() Экспорт
	
	Результат = Новый Структура;
	
	Результат.Вставить("ЭтоКоличествоКоллизий",      Неопределено);
	Результат.Вставить("УчитыватьПроигнорированные", Ложь);
	Результат.Вставить("Период",                     Неопределено);
	Результат.Вставить("СтрокаПоиска",               "");
	
	Возврат Результат;
	
КонецФункции

// Регистрирует ошибки при отложенном проведении документа в мониторе проблем обмена.
//
// Параметры:
//  Объект - ДокументОбъект - документ при отложенном проведении которого возникли ошибки.
//  УзелОбмена - ПланОбменаСсылка - узел информационной базы из которой получен документ.
//  СообщениеОбОшибке - Строка - текст сообщения для журнала регистрации.
//    Рекомендуется передавать в качестве этого параметра ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()).
//    Текст сообщения для отображения в мониторе формируется из системных сообщений пользователю, которые
//    были сформированы, но еще не были выведены пользователю. Поэтому рекомендуется, чтобы к моменту вызова
//    данного метода в буфере сообщений системы не содержалось сообщений.
//  РегистрироватьПроблемыВРезультатахОбмена - Булево - необходимо регистрировать проблемы.
//
// Пример:
// Процедура ПровестиДокументПриЗагрузке(Документ, УзелОбмена)
// Документ.ОбменДанными.Загрузка = Истина;
// Документ.Записать();
// Документ.ОбменДанными.Загрузка = Ложь;
// Отказ = Ложь;
//
// Попытка
// 	Документ.Записать(РежимЗаписиДокумента.Проведение);
// Исключение
// 	СообщениеОбОшибке = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
// 	Отказ = Истина;
// КонецПопытки;
//
// Если Отказ Тогда
// 	ОбменДаннымиСервер.ЗарегистрироватьОшибкуПроведенияДокумента(Документ, УзелОбмена, СообщениеОбОшибке);
// КонецЕсли;
//
// КонецПроцедуры;
//
Процедура ЗарегистрироватьОшибкуПроведенияДокумента(
		Объект,
		УзелОбмена,
		ТекстИсключения,
		РегистрироватьПроблемыВРезультатахОбмена = Истина)
	
	СообщенияПользователю = ПолучитьСообщенияПользователю(Истина);
	ТекстСообщения = ТекстИсключения;
	Для Каждого Сообщение Из СообщенияПользователю Цикл
		
		Если СтрНайти(Сообщение.Текст, "СтандартныеПодсистемы.ДлительныеОперации") > 0 Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		ТекстСообщения = ТекстСообщения + ?(ПустаяСтрока(ТекстСообщения), "", Символы.ПС) + Сообщение.Текст;
		
	КонецЦикла;
	ТекстСообщения = СокрЛП(ТекстСообщения);
	
	СтрокаСообщения = "";
	Если Не ПустаяСтрока(ТекстСообщения) Тогда
		СтрокаСообщения = НСтр("ru = 'Не удалось провести документ %1, полученный из другой информационной базы.
			|По причине: %2.
			|Возможно, не заполнены все реквизиты, обязательные к заполнению.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			СтрокаСообщения, Строка(Объект), ТекстСообщения);
	Иначе
		СтрокаСообщения = НСтр("ru = 'Не удалось провести документ %1, полученный из другой информационной базы.
			|Возможно, не заполнены все реквизиты, обязательные к заполнению.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			СтрокаСообщения, Строка(Объект));
	КонецЕсли;
	
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Предупреждение,,, СтрокаСообщения);
	
	Если РегистрироватьПроблемыВРезультатахОбмена Тогда
		Попытка
			РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьОшибкуПроверкиОбъекта(Объект.Ссылка, УзелОбмена,
				ТекстСообщения, Перечисления.ТипыПроблемОбменаДанными.НепроведенныйДокумент);
		Исключение
			СтрокаСообщения = НСтр("ru = 'Ошибка при записи результата обмена данными для объекта ""%1:
								   |%2'", ОбщегоНазначения.КодОсновногоЯзыка());
			ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
			
			СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, 
				Строка(Объект), ОписаниеОшибки);
			
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Ошибка,,, СтрокаСообщения);	
		КонецПопытки	
	КонецЕсли;
	
КонецПроцедуры

// Регистрирует ошибки при отложенной записи объекта в мониторе проблем обмена.
//
// Параметры:
//   Объект - СправочникОбъект, ДокументОбъект и т.п. - объект, при отложенной записи которого возникли ошибки.
//   УзелОбмена - ПланОбменаСсылка - узел информационной базы из которой получен объект.
//   СообщениеОбОшибке - Строка - текст сообщения для журнала регистрации.
//     Рекомендуется передавать в качестве этого параметра ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()).
//     Текст сообщения для отображения в мониторе формируется из системных сообщений пользователю, которые
//     были сформированы, но еще не были выведены пользователю. Поэтому рекомендуется, чтобы к моменту вызова
//     данного метода в буфере сообщений системы не содержалось сообщений.
//
// Пример:
// Процедура ЗаписатьОбъектПриЗагрузке(Объект, УзелОбмена)
// Объект.ОбменДанными.Загрузка = Истина;
// Объект.Записать();
// Объект.ОбменДанными.Загрузка = Ложь;
// Отказ = Ложь;
//
// Попытка
// 	Объект.Записать();
// Исключение
// 	СообщениеОбОшибке = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
// 	Отказ = Истина;
// КонецПопытки;
//
// Если Отказ Тогда
// 	ОбменДаннымиСервер.ЗарегистрироватьОшибкуЗаписиОбъекта(Объект, УзелОбмена, СообщениеОбОшибке);
// КонецЕсли;
//
// КонецПроцедуры;
//
Процедура ЗарегистрироватьОшибкуЗаписиОбъекта(
		Объект,
		УзелОбмена,
		ТекстИсключения)
	
	СообщенияПользователю = ПолучитьСообщенияПользователю(Истина);
	ТекстСообщения = ТекстИсключения;
	Для Каждого Сообщение Из СообщенияПользователю Цикл
		
		Если СтрНайти(Сообщение.Текст, "СтандартныеПодсистемы.ДлительныеОперации") > 0 Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		ТекстСообщения = ТекстСообщения + ?(ПустаяСтрока(ТекстСообщения), "", Символы.ПС) + Сообщение.Текст;
		
	КонецЦикла;
	
	ПричинаОшибки = ТекстСообщения;
	Если Не ПустаяСтрока(СокрЛП(ТекстСообщения)) Тогда
		
		ПричинаОшибки = " " + НСтр("ru = 'По причине %1.'");
		ПричинаОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ПричинаОшибки, ТекстСообщения);
		
	КонецЕсли;
	
	СтрокаСообщения = НСтр("ru = 'Не удалось записать объект %1, полученный из другой информационной базы.%2
		|Возможно не заполнены все реквизиты, обязательные к заполнению.'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, Строка(Объект), ПричинаОшибки);
	
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Предупреждение,,, СтрокаСообщения);
	
	Попытка
		РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьОшибкуПроверкиОбъекта(Объект.Ссылка, УзелОбмена,
			ТекстСообщения, Перечисления.ТипыПроблемОбменаДанными.НезаполненныеРеквизиты);
	Исключение
		СтрокаСообщения = НСтр("ru = 'Ошибка при записи результата обмена данными для объекта ""%1:
								   |%2'", ОбщегоНазначения.КодОсновногоЯзыка());
		ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, 
			Строка(Объект), ОписаниеОшибки);
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(), УровеньЖурналаРегистрации.Ошибка,,, СтрокаСообщения);		
	КонецПопытки
	
КонецПроцедуры

#КонецОбласти

#Область ПрогрессБар

// Подсчет количества объектов ИБ, подлежащих выгрузке при создании начального образа.
//
// Параметры:
//   Получатель - ПланОбменаОбъект - узел плана обмена, соответствующий получателю.
//
// Возвращаемое значение:
//   Число
//
Функция РассчитатьКоличествоОбъектовВБазе(Получатель)
	
	ИмяПланаОбмена = Получатель.Метаданные().Имя;
	СчетчикОбъектов = 0;
	СоставПланаОбмена = Метаданные.ПланыОбмена[ИмяПланаОбмена].Состав;
	
	// 1. "Ссылочные" объекты.
	СтруктураСсылочныхОбъектов = Новый Структура;
	СтруктураСсылочныхОбъектов.Вставить("Справочник", Метаданные.Справочники);
	СтруктураСсылочныхОбъектов.Вставить("Документ", Метаданные.Документы);
	СтруктураСсылочныхОбъектов.Вставить("ПланВидовХарактеристик", Метаданные.ПланыВидовХарактеристик);
	СтруктураСсылочныхОбъектов.Вставить("ПланВидовРасчета", Метаданные.ПланыВидовРасчета);
	СтруктураСсылочныхОбъектов.Вставить("ПланСчетов", Метаданные.ПланыСчетов);
	СтруктураСсылочныхОбъектов.Вставить("БизнесПроцесс", Метаданные.БизнесПроцессы);
	СтруктураСсылочныхОбъектов.Вставить("Задача", Метаданные.Задачи);
	СтруктураСсылочныхОбъектов.Вставить("ПланСчетов", Метаданные.ПланыСчетов);

	ШаблонТекстаЗапросаСсылки = 
	"ВЫБРАТЬ
	|	КОЛИЧЕСТВО(ПсевдонимТаблицыМетаданных.Ссылка) КАК КоличествоОбъектов
	|ИЗ
	|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных";
	
	Для Каждого СсылочныйОбъект Из СтруктураСсылочныхОбъектов Цикл
		
		Для Каждого ОбъектМетаданных Из СсылочныйОбъект.Значение Цикл
			
			Если СоставПланаОбмена.Найти(ОбъектМетаданных) = Неопределено Тогда
				
				Продолжить;
				
			КонецЕсли;
			
			ПолноеИмяОбъекта = СсылочныйОбъект.Ключ + "." + ОбъектМетаданных.Имя;
			ТекстЗапроса = СтрЗаменить(ШаблонТекстаЗапросаСсылки, "&ИмяТаблицыМетаданных", ПолноеИмяОбъекта);
			
			Запрос = Новый Запрос(ТекстЗапроса);
			Выборка = Запрос.Выполнить().Выбрать();
			Если Выборка.Следующий() Тогда
				
				СчетчикОбъектов = СчетчикОбъектов + Выборка.КоличествоОбъектов;
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
	// 2. Константы.
	Для Каждого ОбъектМетаданных Из Метаданные.Константы Цикл
		Если СоставПланаОбмена.Найти(ОбъектМетаданных) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		СчетчикОбъектов = СчетчикОбъектов + 1;
	КонецЦикла;

	// 3. Регистры сведений.
	ШаблонТекстаЗапросаБезРегистратора = 
	"ВЫБРАТЬ
	|	КОЛИЧЕСТВО(*) КАК КоличествоОбъектов
	|ИЗ
	|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных";
	
	ШаблонТекстаЗапросаСРегистратором = 
	"ВЫБРАТЬ
	|	КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ПсевдонимТаблицыМетаданных.Регистратор) КАК КоличествоОбъектов
	|ИЗ
	|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных";
	
	Для Каждого ОбъектМетаданных Из Метаданные.РегистрыСведений Цикл
		
		Если СоставПланаОбмена.Найти(ОбъектМетаданных) = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		ПолноеИмяОбъекта = "РегистрСведений."+ОбъектМетаданных.Имя;
		Если ОбъектМетаданных.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.ПозицияРегистратора Тогда
			
			ТекстЗапроса = СтрЗаменить(ШаблонТекстаЗапросаСРегистратором, "&ИмяТаблицыМетаданных", ПолноеИмяОбъекта);
			
		Иначе
			
			ТекстЗапроса =  СтрЗаменить(ШаблонТекстаЗапросаБезРегистратора, "&ИмяТаблицыМетаданных", ПолноеИмяОбъекта);
			
		КонецЕсли;
		
		Запрос = Новый Запрос(ТекстЗапроса);
		Выборка = Запрос.Выполнить().Выбрать();
		Если Выборка.Следующий() Тогда
			
			СчетчикОбъектов = СчетчикОбъектов + Выборка.КоличествоОбъектов;
			
		КонецЕсли;
		
	КонецЦикла;
	
	// 4. Регистры (подчиненные регистратору) и последовательности.
	СтруктураРегистров = Новый Структура;
	СтруктураРегистров.Вставить("РегистрНакопления", Метаданные.РегистрыНакопления);
	СтруктураРегистров.Вставить("РегистрРасчета", Метаданные.РегистрыРасчета);
	СтруктураРегистров.Вставить("РегистрБухгалтерии", Метаданные.РегистрыБухгалтерии);
	СтруктураРегистров.Вставить("Последовательность", Метаданные.Последовательности);

	Для Каждого Регистр Из СтруктураРегистров Цикл
		
		Для Каждого ОбъектМетаданных Из Регистр.Значение Цикл
			
			Если СоставПланаОбмена.Найти(ОбъектМетаданных) = Неопределено Тогда
				
				Продолжить;
				
			КонецЕсли;
			
			ПолноеИмяОбъекта = Регистр.Ключ +"."+ОбъектМетаданных.Имя;
			ТекстЗапроса = СтрЗаменить(ШаблонТекстаЗапросаСРегистратором, "&ИмяТаблицыМетаданных", ПолноеИмяОбъекта);
			
			Запрос = Новый Запрос(ТекстЗапроса);
			Выборка = Запрос.Выполнить().Выбрать();
			Если Выборка.Следующий() Тогда
				
				СчетчикОбъектов = СчетчикОбъектов + Выборка.КоличествоОбъектов;
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;

	Возврат СчетчикОбъектов;
	
КонецФункции

// Подсчет количества объектов, зарегистрированных в плане обмена.
//
// Параметры:
//   Получатель - ПланОбменаОбъект
//
// Возвращаемое значение:
//   Число
//
Функция РассчитатьКоличествоЗарегистрированныхОбъектов(Получатель) Экспорт
	
	ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(Получатель.Ссылка, Получатель.НомерОтправленного + 1);
	КоличествоОбъектовКВыгрузке = 0;
	Пока ВыборкаИзменений.Следующий() Цикл
		КоличествоОбъектовКВыгрузке = КоличествоОбъектовКВыгрузке + 1;
	КонецЦикла;
	Возврат КоличествоОбъектовКВыгрузке;
	
КонецФункции

#КонецОбласти

#Область РаботаСКонстантойСообщениеОбменаИзГлавногоУзла

// Зачитывает из информационной базы информацию о сообщении обмена данными.
//
// Возвращаемое значение:
//   Структура - информация о расположении файла сообщения обмена (текущий формат).
//                       - ДвоичныеДанные - сообщение обмена в информационной базе (устаревший формат).
//
Функция СообщениеОбменаДаннымиИзГлавногоУзла() Экспорт
	
	Возврат Константы.СообщениеОбменаДаннымиИзГлавногоУзла.Получить().Получить();
	
КонецФункции

// Записывает на диск файл сообщения обмена, полученный из главного узла.
// Сохраняет путь к записанному сообщению в константу СообщениеОбменаДаннымиИзГлавногоУзла.
//
// Параметры:
//  СообщениеОбмена - ДвоичныеДанные - зачитанное сообщение обмена.
//  ГлавныйУзел - ПланОбменаСсылка - узел из которого получено сообщение.
//
Процедура УстановитьСообщениеОбменаДаннымиИзГлавногоУзла(СообщениеОбмена, ГлавныйУзел) Экспорт
	
	ПутьКФайлу = "[Каталог][Путь].xml";
	ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "[Каталог]", КаталогВременногоХранилищаФайлов());
	ПутьКФайлу = СтрЗаменить(ПутьКФайлу, "[Путь]", Новый УникальныйИдентификатор);
	
	СообщениеОбмена.Записать(ПутьКФайлу);
	
	СтруктураСообщения = Новый Структура;
	СтруктураСообщения.Вставить("ПутьКФайлу", ПутьКФайлу);
	
	Константы.СообщениеОбменаДаннымиИзГлавногоУзла.Установить(Новый ХранилищеЗначения(СтруктураСообщения));
	
	ЗаписатьСобытиеПолученияДанных(ГлавныйУзел, НСтр("ru = 'Сообщение обмена записано в кэш.'"));
	
КонецПроцедуры

// Удаляет файл сообщения обмена с диска и очищает константу СообщениеОбменаДаннымиИзГлавногоУзла.
//
Процедура ОчиститьСообщениеОбменаДаннымиИзГлавногоУзла() Экспорт
	
	СообщениеОбмена = СообщениеОбменаДаннымиИзГлавногоУзла();
	
	Если ТипЗнч(СообщениеОбмена) = Тип("Структура") Тогда
		
		УдалитьФайлы(СообщениеОбмена.ПутьКФайлу);
		
	КонецЕсли;
	
	Константы.СообщениеОбменаДаннымиИзГлавногоУзла.Установить(Новый ХранилищеЗначения(Неопределено));
	
	ЗаписатьСобытиеПолученияДанных(ГлавныйУзел(), НСтр("ru = 'Сообщение обмена удалено из кэша.'"));
	
КонецПроцедуры

#КонецОбласти

#Область ПрофилиБезопасности

Процедура СформироватьЗапросыНаИспользованиеВнешнихРесурсов(ЗапросыРазрешений)
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	Константы.КаталогСообщенийОбменаДаннымиДляLinux.СоздатьМенеджерЗначения().ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений);
	Константы.КаталогСообщенийОбменаДаннымиДляWindows.СоздатьМенеджерЗначения().ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений);
	
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		РегистрыСведений.НастройкиТранспортаОбменаДанными.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений);
	КонецЕсли;
	
	РегистрыСведений.ПравилаДляОбменаДанными.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений);
	
КонецПроцедуры

// Параметры:
//   ЗапросыРазрешений - Массив из УникальныйИдентификатор - коллекция запросов разрешений.
//   Объект - КонстантаМенеджерЗначения - менеджер значения объекта данных.
//
Процедура ЗапросВнешнихРесурсовДляКаталогаСообщенийОбменаДанными(ЗапросыРазрешений, Объект) Экспорт
	
	ЗначениеКонстанты = Объект.Значение;
	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
	Если Не ПустаяСтрока(ЗначениеКонстанты) Тогда
		
		Разрешения = Новый Массив;
		Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеКаталогаФайловойСистемы(
			ЗначениеКонстанты, Истина, Истина));
		
		ЗапросыРазрешений.Добавить(
			МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(Разрешения,
				ОбщегоНазначения.ИдентификаторОбъектаМетаданных(Объект.Метаданные())));
		
	КонецЕсли;
	
КонецПроцедуры

// Возвращает шаблон имени профиля безопасности для внешнего модуля.
// Функция должна возвращать одно и то же значение при многократном вызове.
//
// Параметры:
//  ВнешнийМодуль - ЛюбаяСсылка - ссылка на внешний модуль.
//
// Возвращаемое значение:
//   Строка - шаблон имя профиля безопасности, содержащий символы
//  "%1", вместо которых в дальнейшем будет подставлен уникальный идентификатор.
//
Функция ШаблонИмениПрофиляБезопасности(Знач ВнешнийМодуль) Экспорт
	
	Шаблон = "Exchange_[ИмяПланаОбмена]_%1"; // Не локализуется
	Возврат СтрЗаменить(Шаблон, "[ИмяПланаОбмена]", ВнешнийМодуль.Имя);
	
КонецФункции

// Возвращает пиктограмму, отображающую внешний модуль.
//
//  ВнешнийМодуль - ЛюбаяСсылка, ссылка на внешний модуль,
//
// Возвращаемое значение:
//   Картинка.
//
Функция ПиктограммаВнешнегоМодуля(Знач ВнешнийМодуль) Экспорт
	
	Возврат БиблиотекаКартинок.СинхронизацияДанных;
	
КонецФункции

Функция СловарьКонтейнераВнешнегоМодуля() Экспорт
	
	Результат = Новый Структура();
	
	Результат.Вставить("Именительный", НСтр("ru = 'Настройка синхронизации данных'"));
	Результат.Вставить("Родительный",  НСтр("ru = 'Настройки синхронизации данных'"));
	
	Возврат Результат;
	
КонецФункции

Функция КонтейнерыВнешнихМодулей() Экспорт
	
	Результат = Новый Массив();
	ОбменДаннымиПереопределяемый.ПолучитьПланыОбмена(Результат);
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область ВыполнениеДействий

Процедура ВыполнитьДействиеОбменаДляУзлаИнформационнойБазыПоВнешнемуСоединению(Отказ, УзелИнформационнойБазы,
	ДействиеПриОбмене,
	КоличествоЭлементовВТранзакции,
	СообщениеДляСопоставленияДанных = Ложь)
	
	УстановитьПривилегированныйРежим(Истина);
	
	// ИНИЦИАЛИЗАЦИЯ ОБМЕНА ДАННЫМИ
	СтруктураНастроекОбмена = НастройкиОбменаДляВнешнегоСоединения(
		УзелИнформационнойБазы,
		ДействиеПриОбмене,
		КоличествоЭлементовВТранзакции);
	
	ЗаписьЖурналаРегистрацииНачалаОбменаДанными(СтруктураНастроекОбмена);
	
	Если СтруктураНастроекОбмена.Отказ Тогда
		// Если настройка содержит ошибки, то обмен не производим; статус "Отменено".
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Отменено;
		ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
		Отказ = Истина;
		Возврат;
	КонецЕсли;
	
	СтрокаСообщенияОбОшибке = "";
	
	// Получаем внешнее соединение для узла информационной базы.
	ВнешнееСоединение = ОбменДаннымиПовтИсп.ПолучитьВнешнееСоединениеДляУзлаИнформационнойБазы(
		УзелИнформационнойБазы,
		СтрокаСообщенияОбОшибке);
	
	Если ВнешнееСоединение = Неопределено Тогда
		
		// добавляем запись в ЖР
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		
		// Если настройка содержит ошибки, то обмен не производим; статус "Отменено".
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Отменено;
		ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
		Отказ = Истина;
		Возврат;
	КонецЕсли;
	
	// Получаем версию удаленной базы.
	ВерсияБСППоВнешнемуСоединению = ВнешнееСоединение.СтандартныеПодсистемыСервер.ВерсияБиблиотеки();
	ОбменСБСП20 = ОбщегоНазначенияКлиентСервер.СравнитьВерсии("2.1.1.10", ВерсияБСППоВнешнемуСоединению) > 0;
	
	// ИНИЦИАЛИЗАЦИЯ ОБМЕНА ДАННЫМИ (ВНЕШНЕЕ СОЕДИНЕНИЕ)
	Структура = Новый Структура("ИмяПланаОбмена, ИмяПланаОбменаКорреспондента, 
		|ТекущийУзелПланаОбменаКод, КоличествоЭлементовВТранзакции");
	
	ЗаполнитьЗначенияСвойств(Структура, СтруктураНастроекОбмена);
	
	// Выполняем реверс значений перечисления.
	ДействиеПриОбменеСтрокой = ?(ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ВыгрузкаДанных,
								ОбщегоНазначения.ИмяЗначенияПеречисления(Перечисления.ДействияПриОбмене.ЗагрузкаДанных),
								ОбщегоНазначения.ИмяЗначенияПеречисления(Перечисления.ДействияПриОбмене.ВыгрузкаДанных));
	//
	
	Структура.Вставить("ДействиеПриОбменеСтрокой", ДействиеПриОбменеСтрокой);
	Структура.Вставить("РежимОтладки", Ложь);
	Структура.Вставить("ИмяФайлаПротоколаОбмена", "");
	
	ЭтоПланОбменаXDTO = ЭтоПланОбменаXDTO(УзелИнформационнойБазы);
	Если ЭтоПланОбменаXDTO Тогда
		// Проверка псевдонима предопределенного узла
		ПсевдонимПредопределенногоУзла = ПсевдонимПредопределенногоУзла(УзелИнформационнойБазы);
		ПланОбменаМенеджер = ВнешнееСоединение.ПланыОбмена[Структура.ИмяПланаОбменаКорреспондента];
		ПроверятьНаличиеУзлаВКорреспонденте = Истина;
		Если ЗначениеЗаполнено(ПсевдонимПредопределенногоУзла) Тогда
			// Надо проверить код узла в корреспонденте - он может быть уже перекодирован.
			// Тогда псевдоним больше не нужен.
			Если ПланОбменаМенеджер.НайтиПоКоду(ПсевдонимПредопределенногоУзла) <> ПланОбменаМенеджер.ПустаяСсылка() Тогда
				Структура.ТекущийУзелПланаОбменаКод = ПсевдонимПредопределенногоУзла;
				ПроверятьНаличиеУзлаВКорреспонденте = Ложь;
			КонецЕсли;
		КонецЕсли;
		Если ПроверятьНаличиеУзлаВКорреспонденте Тогда
			ПланОбменаСсылка = ПланОбменаМенеджер.НайтиПоКоду(Структура.ТекущийУзелПланаОбменаКод);
			Если НЕ ЗначениеЗаполнено(ПланОбменаСсылка.Code) Тогда
				// При необходимости запуск перехода на синхронизацию данных через универсальный формат.
				ТекстСообщения = НСтр("ru = 'Необходим переход на синхронизацию данных через универсальный формат в базе-корреспонденте.'");
				ЗаписьЖурналаРегистрацииОбменаДанными(ТекстСообщения, СтруктураНастроекОбмена, Ложь);

				СтруктураПараметров = Новый Структура();
				СтруктураПараметров.Вставить("Код", Структура.ТекущийУзелПланаОбменаКод);
				СтруктураПараметров.Вставить("ВариантНастройки", 
					ОбщегоНазначения.ЗначениеРеквизитаОбъекта(УзелИнформационнойБазы, "ВариантНастройки"));
				СтруктураПараметров.Вставить("Ошибка", Ложь);
				СтруктураПараметров.Вставить("СообщениеОбОшибке", "");
				
				ЕстьОшибки = Ложь;
				СтрокаСообщенияОбОшибке = "";
				РезультатПерехода = 
					ПланОбменаМенеджер.ПереходНаСинхронизациюЧерезУниверсальныйФорматВнешнееСоединение(СтруктураПараметров);
				Если СтруктураПараметров.Ошибка Тогда
					ЕстьОшибки = Истина;
					НСтрока = НСтр("ru = 'Ошибка при переходе на синхронизацию данных через универсальный формат: %1. Обмен отменен.'",
						ОбщегоНазначения.КодОсновногоЯзыка());
					СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтрока, 
						СтруктураПараметров.СообщениеОбОшибке);
				ИначеЕсли РезультатПерехода = Неопределено Тогда
					ЕстьОшибки = Истина;
					СтрокаСообщенияОбОшибке = НСтр("ru = 'Переход на синхронизацию данных через универсальный формат не выполнен'");
				КонецЕсли;
				Если ЕстьОшибки Тогда
					ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
					СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Отменено;
					ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
					Отказ = Истина;
					Возврат;
				Иначе
					Сообщение = НСтр("ru = 'Переход на синхронизацию данных через универсальный формат завершен успешно.'");
					ЗаписьЖурналаРегистрацииОбменаДанными(Сообщение, СтруктураНастроекОбмена, Ложь);
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	СтруктураКорреспондента = ОбщегоНазначения.СкопироватьРекурсивно(Структура, Ложь);
	СтруктураКорреспондента.ИмяПланаОбмена = Структура.ИмяПланаОбменаКорреспондента;
	СтруктураКорреспондента.ИмяПланаОбменаКорреспондента = Структура.ИмяПланаОбмена;
	
	Попытка
		СтруктураНастроекОбменаВнешнееСоединение = ВнешнееСоединение.ОбменДаннымиВнешнееСоединение.СтруктураНастроекОбмена(СтруктураКорреспондента);
	Исключение
		ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),
			СтруктураНастроекОбмена, Истина);
		
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Отменено;
		ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
		Отказ = Истина;
		Возврат;
	КонецПопытки;
	
	Если СтруктураНастроекОбменаВнешнееСоединение.Свойство("НастройкаСинхронизацииДанныхЗавершена") Тогда
		Если Не СообщениеДляСопоставленияДанных
			И СтруктураНастроекОбменаВнешнееСоединение.НастройкаСинхронизацииДанныхЗавершена = Ложь Тогда
			
			СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Для продолжения перейдите в программу ""%1"" и завершите в ней настройку синхронизации.
				|Выполнение обмена данными отменено.'"),
				СтруктураНастроекОбменаВнешнееСоединение.УзелИнформационнойБазыНаименование);
			ЗаписьЖурналаРегистрацииОбменаДанными(СообщениеОбОшибке, СтруктураНастроекОбмена, Истина);
			
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Отменено;
			ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
			Отказ = Истина;
			Возврат;
			
		КонецЕсли;
	КонецЕсли;
	
	Если СтруктураНастроекОбменаВнешнееСоединение.Свойство("ПолученоСообщениеДляСопоставленияДанных") Тогда
		Если Не СообщениеДляСопоставленияДанных
			И СтруктураНастроекОбменаВнешнееСоединение.ПолученоСообщениеДляСопоставленияДанных = Истина Тогда
			
			СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Для продолжения перейдите в программу ""%1"" и выполните загрузку сообщения для сопоставления данных.
				|Выполнение обмена данными отменено.'"),
				СтруктураНастроекОбменаВнешнееСоединение.УзелИнформационнойБазыНаименование);
			ЗаписьЖурналаРегистрацииОбменаДанными(СообщениеОбОшибке, СтруктураНастроекОбмена, Истина);
			
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Отменено;
			ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
			Отказ = Истина;
			Возврат;
			
		КонецЕсли;
	КонецЕсли;
	
	СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено;
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ДатаНачала", ВнешнееСоединение.ТекущаяДатаСеанса());
	
	ВнешнееСоединение.ОбменДаннымиВнешнееСоединение.ЗаписьЖурналаРегистрацииНачалаОбменаДанными(СтруктураНастроекОбменаВнешнееСоединение);
	// ОБМЕН ДАННЫМИ
	Если СтруктураНастроекОбмена.ПроизводитьЗагрузкуДанных Тогда
		Если НЕ ЭтоПланОбменаXDTO Тогда
			// Получаем правила обмена из второй ИБ.
			ПравилаКонвертацииОбъектов = ВнешнееСоединение.ОбменДаннымиВнешнееСоединение.ПолучитьПравилаКонвертацииОбъектов(СтруктураНастроекОбменаВнешнееСоединение.ИмяПланаОбмена);
			
			Если ПравилаКонвертацииОбъектов = Неопределено Тогда
				
				// Правила обмена должны быть указаны.
				НСтрока = НСтр("ru = 'Не заданы правила конвертации во второй информационной базе для плана обмена %1. Обмен отменен.'",
					ОбщегоНазначения.КодОсновногоЯзыка());
				СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтрока, СтруктураНастроекОбменаВнешнееСоединение.ИмяПланаОбмена);
				ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
				ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
				Возврат;
			КонецЕсли;
		КонецЕсли;
		
		// Обработка для загрузки данных.
		ОбработкаДляЗагрузкиДанных = СтруктураНастроекОбмена.ОбработкаОбменаДанными;
		ОбработкаДляЗагрузкиДанных.ИмяФайлаОбмена = "";
		ОбработкаДляЗагрузкиДанных.КоличествоОбъектовНаТранзакцию = СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции;
		ОбработкаДляЗагрузкиДанных.ИспользоватьТранзакции = (ОбработкаДляЗагрузкиДанных.КоличествоОбъектовНаТранзакцию <> 1);
		ОбработкаДляЗагрузкиДанных.ЗагрузкаДанныхВыполняетсяЧерезВнешнееСоединение = Истина;
		
		// Получаем инициализированную обработку для выгрузки данных.
		Если ЭтоПланОбменаXDTO Тогда
			ОбработкаОбменаДаннымиВнешнееСоединение = ВнешнееСоединение.Обработки.КонвертацияОбъектовXDTO.Создать();
			ОбработкаОбменаДаннымиВнешнееСоединение.РежимОбмена = "Выгрузка";
		Иначе
			ОбработкаОбменаДаннымиВнешнееСоединение = ВнешнееСоединение.Обработки.КонвертацияОбъектовИнформационныхБаз.Создать();
			ОбработкаОбменаДаннымиВнешнееСоединение.СохраненныеНастройки = ПравилаКонвертацииОбъектов;
			ОбработкаОбменаДаннымиВнешнееСоединение.ЗагрузкаДанныхВыполняетсяВоВнешнемСоединении = Ложь;
			ОбработкаОбменаДаннымиВнешнееСоединение.РежимОбмена = "Выгрузка";
			Попытка
				ОбработкаОбменаДаннымиВнешнееСоединение.ВосстановитьПравилаИзВнутреннегоФормата();
			Исключение
				ЗаписьЖурналаРегистрацииОбменаДанными(
					СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Возникла ошибка во второй информационной базе: %1'"),
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())), СтруктураНастроекОбмена, Истина);
				
				// Если настройка содержит ошибки, то обмен не производим; статус "Отменено".
				СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Отменено;
				ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
				Отказ = Истина;
				Возврат;
			КонецПопытки;
			// Задаем узлы обмена.
			ОбработкаОбменаДаннымиВнешнееСоединение.УзелДляФоновогоОбмена = Неопределено;
			ОбработкаОбменаДаннымиВнешнееСоединение.НеВыгружатьОбъектыПоСсылкам = Истина;
			ОбработкаОбменаДаннымиВнешнееСоединение.ИмяФайлаПравилОбмена = "1";
			ОбработкаОбменаДаннымиВнешнееСоединение.ВнешнееСоединение = Неопределено;
		КонецЕсли;

		ОбработкаОбменаДаннымиВнешнееСоединение.УзелДляОбмена = СтруктураНастроекОбменаВнешнееСоединение.УзелИнформационнойБазы;
		Если ОбработкаОбменаДаннымиВнешнееСоединение.Метаданные().Реквизиты.Найти("УстановитьБлокировкуУзлаПланаОбмена") <> Неопределено Тогда
			
			ОбработкаОбменаДаннымиВнешнееСоединение.УстановитьБлокировкуУзлаПланаОбмена = Истина;
			
		КонецЕсли;
		
		УстановитьОбщиеПараметрыДляОбработкиОбменаДанными(ОбработкаОбменаДаннымиВнешнееСоединение, СтруктураНастроекОбменаВнешнееСоединение, ОбменСБСП20);
		
		Если НЕ ЭтоПланОбменаXDTO Тогда
			ВерсияКонфигурацииПриемника = "";
			ВерсияИсточникаИзПравил = "";
			ТекстСообщения = "";
			ПараметрыВнешнегоСоединения = Новый Структура;
			ПараметрыВнешнегоСоединения.Вставить("ВнешнееСоединение", ВнешнееСоединение);
			ПараметрыВнешнегоСоединения.Вставить("ВерсияБСППоВнешнемуСоединению", ВерсияБСППоВнешнемуСоединению);
			ПараметрыВнешнегоСоединения.Вставить("КлючСообщенияЖурналаРегистрации", СтруктураНастроекОбменаВнешнееСоединение.КлючСообщенияЖурналаРегистрации);
			ПараметрыВнешнегоСоединения.Вставить("УзелИнформационнойБазы", СтруктураНастроекОбменаВнешнееСоединение.УзелИнформационнойБазы);
			
			ПравилаКонвертацииОбъектов.Получить().Конвертация.Свойство("ВерсияКонфигурацииИсточника", ВерсияКонфигурацииПриемника);
			ОбработкаДляЗагрузкиДанных.СохраненныеНастройки.Получить().Конвертация.Свойство("ВерсияКонфигурацииИсточника", ВерсияИсточникаИзПравил);
			
			Если РазличаютсяВерсииКорреспондента(СтруктураНастроекОбмена.ИмяПланаОбмена, СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации,
				ВерсияИсточникаИзПравил, ВерсияКонфигурацииПриемника, ТекстСообщения, ПараметрыВнешнегоСоединения) Тогда
				
				ОбработкаОбменаДаннымиВнешнееСоединение = Неопределено;
				Возврат;
				
			КонецЕсли;
		КонецЕсли;
		// ВЫГРУЗКА (КОРРЕСПОНДЕНТ) - ЗАГРУЗКА (ЭТА БАЗА)
		ОбработкаОбменаДаннымиВнешнееСоединение.ВыполнитьВыгрузкуДанных(ОбработкаДляЗагрузкиДанных);
		
		// Фиксируем состояние выполнения обмена данными.
		СтруктураНастроекОбмена.РезультатВыполненияОбмена    = ОбработкаДляЗагрузкиДанных.РезультатВыполненияОбмена();
		СтруктураНастроекОбмена.КоличествоОбъектовОбработано = ОбработкаДляЗагрузкиДанных.СчетчикЗагруженныхОбъектов();
		СтруктураНастроекОбменаВнешнееСоединение.РезультатВыполненияОбменаСтрокой = ОбработкаОбменаДаннымиВнешнееСоединение.РезультатВыполненияОбменаСтрокой();
		СтруктураНастроекОбменаВнешнееСоединение.КоличествоОбъектовОбработано     = ОбработкаОбменаДаннымиВнешнееСоединение.СчетчикВыгруженныхОбъектов();
		СтруктураНастроекОбмена.СообщениеПриОбмене           = ОбработкаДляЗагрузкиДанных.КомментарийПриЗагрузкеДанных;
		СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке      = ОбработкаДляЗагрузкиДанных.СтрокаСообщенияОбОшибке();
		СтруктураНастроекОбменаВнешнееСоединение.СообщениеПриОбмене               = ОбработкаОбменаДаннымиВнешнееСоединение.КомментарийПриВыгрузкеДанных;
		СтруктураНастроекОбменаВнешнееСоединение.СтрокаСообщенияОбОшибке          = ОбработкаОбменаДаннымиВнешнееСоединение.СтрокаСообщенияОбОшибке();
		
		ОбработкаОбменаДаннымиВнешнееСоединение = Неопределено;
		
	ИначеЕсли СтруктураНастроекОбмена.ПроизводитьВыгрузкуДанных Тогда
				
		// Обработка для загрузки данных.
		Если ЭтоПланОбменаXDTO Тогда
			ОбработкаДляЗагрузкиДанных = ВнешнееСоединение.Обработки.КонвертацияОбъектовXDTO.Создать();
		Иначе
			ОбработкаДляЗагрузкиДанных = ВнешнееСоединение.Обработки.КонвертацияОбъектовИнформационныхБаз.Создать();
			ОбработкаДляЗагрузкиДанных.ЗагрузкаДанныхВыполняетсяЧерезВнешнееСоединение = Истина;
		КонецЕсли;
		ОбработкаДляЗагрузкиДанных.РежимОбмена = "Загрузка";
		ОбработкаДляЗагрузкиДанных.УзелОбменаЗагрузкаДанных = СтруктураНастроекОбменаВнешнееСоединение.УзелИнформационнойБазы;
		
		УстановитьОбщиеПараметрыДляОбработкиОбменаДанными(ОбработкаДляЗагрузкиДанных, СтруктураНастроекОбменаВнешнееСоединение, ОбменСБСП20);
		
		ЕстьПоддержкаСопоставления            = Истина;
		НастройкаСинхронизацииДанныхЗавершена = Истина;
		ВерсииИнтерфейса = ВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение);

		Если ВерсииИнтерфейса.Найти("3.0.1.1") <> Неопределено
			Или ВерсииИнтерфейса.Найти("3.0.2.1") <> Неопределено Тогда
			
			СообщениеОбОшибке = "";
			ПараметрыИнформационнойБазы = ВнешнееСоединение.ОбменДаннымиВнешнееСоединение.ПолучитьПараметрыИнформационнойБазы_2_0_1_6(
				СтруктураНастроекОбмена.ИмяПланаОбмена, СтруктураНастроекОбмена.ТекущийУзелПланаОбменаКод, СообщениеОбОшибке);
			ПараметрыКорреспондента = ОбщегоНазначения.ЗначениеИзСтрокиXML(ПараметрыИнформационнойБазы);
			Если ПараметрыКорреспондента.Свойство("ПоддерживаетсяСопоставлениеДанных") Тогда
				ЕстьПоддержкаСопоставления = ПараметрыКорреспондента.ПоддерживаетсяСопоставлениеДанных;
			КонецЕсли;
			Если ПараметрыКорреспондента.Свойство("НастройкаСинхронизацииДанныхЗавершена") Тогда
				НастройкаСинхронизацииДанныхЗавершена = ПараметрыКорреспондента.НастройкаСинхронизацииДанныхЗавершена;
			КонецЕсли;
			
		КонецЕсли;
		
		Если СообщениеДляСопоставленияДанных
			И (ЕстьПоддержкаСопоставления Или Не НастройкаСинхронизацииДанныхЗавершена) Тогда
			ОбработкаДляЗагрузкиДанных.РежимЗагрузкиДанных = "ЗагрузкаСообщенияДляСопоставленияДанных";
		КонецЕсли;
		
		ОбработкаДляЗагрузкиДанных.КоличествоОбъектовНаТранзакцию = СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции;
		ОбработкаДляЗагрузкиДанных.ИспользоватьТранзакции = (ОбработкаДляЗагрузкиДанных.КоличествоОбъектовНаТранзакцию <> 1);
		
		// Получаем инициализированную обработку для выгрузки данных.
		ОбработкаОбменаДаннымиXML = СтруктураНастроекОбмена.ОбработкаОбменаДанными; //ОбработкаОбъект.КонвертацияОбъектовXDTO
		ОбработкаОбменаДаннымиXML.ИмяФайлаОбмена = "";
		
		Если Не ЭтоПланОбменаXDTO Тогда
			
			ОбработкаОбменаДаннымиXML.ВнешнееСоединение = ВнешнееСоединение;
			ОбработкаОбменаДаннымиXML.ЗагрузкаДанныхВыполняетсяВоВнешнемСоединении = Истина;
			
		КонецЕсли;
		
		// ВЫГРУЗКА (ЭТА БАЗА) - ЗАГРУЗКА (КОРРЕСПОНДЕНТ)
		ОбработкаОбменаДаннымиXML.ВыполнитьВыгрузкуДанных(ОбработкаДляЗагрузкиДанных);
		
		// Фиксируем состояние выполнения обмена данными.
		СтруктураНастроекОбмена.РезультатВыполненияОбмена    = ОбработкаОбменаДаннымиXML.РезультатВыполненияОбмена();
		СтруктураНастроекОбмена.КоличествоОбъектовОбработано = ОбработкаОбменаДаннымиXML.СчетчикВыгруженныхОбъектов();
		СтруктураНастроекОбменаВнешнееСоединение.РезультатВыполненияОбменаСтрокой = ОбработкаДляЗагрузкиДанных.РезультатВыполненияОбменаСтрокой();
		СтруктураНастроекОбменаВнешнееСоединение.КоличествоОбъектовОбработано     = ОбработкаДляЗагрузкиДанных.СчетчикЗагруженныхОбъектов();
		СтруктураНастроекОбмена.СообщениеПриОбмене           = ОбработкаОбменаДаннымиXML.КомментарийПриВыгрузкеДанных;
		СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке      = ОбработкаОбменаДаннымиXML.СтрокаСообщенияОбОшибке();
		СтруктураНастроекОбменаВнешнееСоединение.СообщениеПриОбмене               = ОбработкаДляЗагрузкиДанных.КомментарийПриЗагрузкеДанных;
		СтруктураНастроекОбменаВнешнееСоединение.СтрокаСообщенияОбОшибке          = ОбработкаДляЗагрузкиДанных.СтрокаСообщенияОбОшибке();
		ОбработкаДляЗагрузкиДанных = Неопределено;
		
	КонецЕсли;
	
	ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
	
	ВнешнееСоединение.ОбменДаннымиВнешнееСоединение.ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбменаВнешнееСоединение);
	
	Если Не РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена) Тогда
		
		Отказ = Истина;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьОбменДаннымиЧерезФайловыйРесурс(СтруктураНастроекОбмена, Знач ТолькоПараметры = Ложь)
	
	Если СтруктураНастроекОбмена.ПроизводитьЗагрузкуДанных Тогда
		
		Если СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.ВнешняяСистема Тогда
			ВыполнитьОбменДаннымиСВнешнейСистемойЗагрузкаДанных(СтруктураНастроекОбмена);
			Возврат;
		КонецЕсли;
		
		// {Обработчик: ПередЧтениемСообщенияОбмена} Начало
		СообщениеОбмена = "";
		СтандартнаяОбработка = Истина;
		
		ПередЧтениемСообщенияОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы, СообщениеОбмена, СтандартнаяОбработка);
		// {Обработчик: ПередЧтениемСообщенияОбмена} Окончание
		
		Если СтандартнаяОбработка Тогда
			
			ВыполнитьТранспортСообщенияОбменаПередОбработкой(СтруктураНастроекОбмена);
			
			Если СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено Тогда
				
				ВыполнитьТранспортСообщенияОбменаПолучение(СтруктураНастроекОбмена);
				
				Если СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено Тогда
					
					СообщениеОбмена = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена.ИмяФайлаСообщенияОбмена();
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
			
		// Загрузка данных только при успешном получении сообщения обмена.
		Если СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено Тогда
			
			ЕстьПоддержкаСопоставления = ЗначениеНастройкиПланаОбмена(
				ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы),
				"ПоддерживаетсяСопоставлениеДанных",
				СохраненныйВариантНастройкиУзлаПланаОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы));
			
			Если СтруктураНастроекОбмена.ДополнительныеПараметры.Свойство("СообщениеДляСопоставленияДанных")
				И (ЕстьПоддержкаСопоставления 
					Или Не НастройкаСинхронизацииЗавершена(СтруктураНастроекОбмена.УзелИнформационнойБазы)) Тогда
				
				ИмяФайлаДляПомещенияВХранилище = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
					КаталогВременногоХранилищаФайлов(),
					УникальноеИмяФайлаСообщенияОбмена());
					
				// Сохраняется новое сообщение для сопоставления данных.
				ИдентификаторФайла = ПоместитьФайлВХранилище(ИмяФайлаДляПомещенияВХранилище);
				ПереместитьФайл(СообщениеОбмена, ИмяФайлаДляПомещенияВХранилище);
				
				ОбменДаннымиСлужебный.ПоместитьСообщениеДляСопоставленияДанных(
					СтруктураНастроекОбмена.УзелИнформационнойБазы, ИдентификаторФайла);
				
				СтандартнаяОбработка = Истина;
			Иначе
				
				ПрочитатьСообщениеСИзменениямиДляУзла(СтруктураНастроекОбмена, СообщениеОбмена, , ТолькоПараметры);
				
				// {Обработчик: ПослеЧтенияСообщенияОбмена} Начало
				СтандартнаяОбработка = Истина;
				
				ПослеЧтенияСообщенияОбмена(
							СтруктураНастроекОбмена.УзелИнформационнойБазы,
							СообщениеОбмена,
							РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена),
							СтандартнаяОбработка,
							Не ТолькоПараметры);
				// {Обработчик: ПослеЧтенияСообщенияОбмена} Окончание
				
			КонецЕсли;
			
		КонецЕсли;
		
		// {Обработчик: ПослеЧтенияСообщенияОбмена} Начало
		СтандартнаяОбработка = Истина;
		
		ПослеЧтенияСообщенияОбмена(
					СтруктураНастроекОбмена.УзелИнформационнойБазы,
					СообщениеОбмена,
					РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена),
					СтандартнаяОбработка,
					Не ТолькоПараметры);
		// {Обработчик: ПослеЧтенияСообщенияОбмена} Окончание
		
		Если СтандартнаяОбработка Тогда
			
			ВыполнитьТранспортСообщенияОбменаПослеОбработки(СтруктураНастроекОбмена);
			
		КонецЕсли;
		
	ИначеЕсли СтруктураНастроекОбмена.ПроизводитьВыгрузкуДанных Тогда
		
		Если СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.ВнешняяСистема Тогда
			ВыполнитьОбменДаннымиСВнешнейСистемойВыгрузкаНастроекXDTO(СтруктураНастроекОбмена);
			Возврат;
		КонецЕсли;
		
		ВыполнитьТранспортСообщенияОбменаПередОбработкой(СтруктураНастроекОбмена);
		
		// выгрузка данных
		Если СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено Тогда
			
			ЗаписатьСообщениеСИзменениямиДляУзла(СтруктураНастроекОбмена, СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена.ИмяФайлаСообщенияОбмена());
			
		КонецЕсли;
		
		// Отправка сообщения обмена только в случае успешной выгрузки данных.
		Если РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена) Тогда
			
			ВыполнитьТранспортСообщенияОбменаОтправка(СтруктураНастроекОбмена);
			
		КонецЕсли;
		
		ВыполнитьТранспортСообщенияОбменаПослеОбработки(СтруктураНастроекОбмена);
		
	КонецЕсли;
	
КонецПроцедуры

// Выполняет процесс обмена данными отдельно для каждой строки сценария (настройки) обмена.
// Процесс обмена данными состоит из двух стадий:
// - инициализация обмена - подготовка подсистемы обмена данными к процессу обмена
// - обмен данными        - процесс зачитывания файла сообщения с последующей загрузкой этих данных в ИБ 
//                          или выгрузки изменений в файл сообщения.
// Стадия инициализации выполняется один раз за сеанс и сохраняется в кэше сеанса на сервере 
// до перезапуска сеанса или сброса повторно-используемых значений подсистемы обмена данными.
// Сброс повторно-используемых значений происходит при изменении данных, влияющих на процесс обмена данными
// (настройки транспорта, настройка выполнения обмена, настройка отборов на узлах планов обмена).
//
// Обмен может быть выполнен полностью для всех строк сценария,
// а может быть выполнен для отдельной строки ТЧ сценария обмена.
//
// Параметры:
//  Отказ                     - Булево - флаг отказа; поднимается в случае возникновения ошибки при выполнении сценария.
//  НастройкаВыполненияОбмена - СправочникСсылка.СценарииОбменовДанными - элемент справочника,
//                              по значениям реквизитов которого будет выполнен обмен данными.
//  НомерСтроки               - Число - номер строки по которой будет выполнен обмен данными.
//                              Если не указан, то обмен данными будет выполнен для всех строк.
// 
Процедура ВыполнитьОбменДаннымиПоСценариюОбменаДанными(Отказ, НастройкаВыполненияОбмена, НомерСтроки = Неопределено) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ЭтоПодчиненныйУзелРИБТребующийУстановкиОбновления = (ЭтоПодчиненныйУзелРИБ() И ТребуетсяУстановкаОбновления());
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	НастройкиВыполненияОбменаНастройкиОбмена.Ссылка                         КАК НастройкаВыполненияОбмена,
	|	НастройкиВыполненияОбменаНастройкиОбмена.НомерСтроки                    КАК НомерСтроки,
	|	НастройкиВыполненияОбменаНастройкиОбмена.ВыполняемоеДействие            КАК ВыполняемоеДействие,
	|	НастройкиВыполненияОбменаНастройкиОбмена.ВидТранспортаОбмена            КАК ВидТранспортаОбмена,
	|	НастройкиВыполненияОбменаНастройкиОбмена.УзелИнформационнойБазы         КАК УзелИнформационнойБазы,
	|
	|	ВЫБОР КОГДА НастройкиВыполненияОбменаНастройкиОбмена.ВидТранспортаОбмена = ЗНАЧЕНИЕ(Перечисление.ВидыТранспортаСообщенийОбмена.COM)
	|		ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК ОбменЧерезВнешнееСоединение,
	|
	|	ВЫБОР КОГДА НастройкиВыполненияОбменаНастройкиОбмена.ВидТранспортаОбмена = ЗНАЧЕНИЕ(Перечисление.ВидыТранспортаСообщенийОбмена.WS)
	|		ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК ОбменЧерезВебСервис,
	|
	|	ВЫБОР КОГДА НастройкиВыполненияОбменаНастройкиОбмена.ВидТранспортаОбмена = ЗНАЧЕНИЕ(Перечисление.ВидыТранспортаСообщенийОбмена.ВнешняяСистема)
	|		ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК ОбменСВнешнейСистемой
	|ИЗ
	|	Справочник.СценарииОбменовДанными.НастройкиОбмена КАК НастройкиВыполненияОбменаНастройкиОбмена
	|ГДЕ
	|	НастройкиВыполненияОбменаНастройкиОбмена.Ссылка = &НастройкаВыполненияОбмена
	|		И &УсловиеПоНомеруСтроки
	|
	|УПОРЯДОЧИТЬ ПО
	|	НастройкиВыполненияОбменаНастройкиОбмена.НомерСтроки";
	
	УсловиеПоНомеруСтроки = ?(НомерСтроки = Неопределено, "", "И НастройкиВыполненияОбменаНастройкиОбмена.НомерСтроки = &НомерСтроки");
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "И &УсловиеПоНомеруСтроки", УсловиеПоНомеруСтроки);
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("НастройкаВыполненияОбмена", НастройкаВыполненияОбмена);
	Запрос.УстановитьПараметр("НомерСтроки", НомерСтроки);
	
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Если ЭтоПодчиненныйУзелРИБТребующийУстановкиОбновления
			И ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(Выборка.УзелИнформационнойБазы) Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		Если Не НастройкаСинхронизацииЗавершена(Выборка.УзелИнформационнойБазы)
			И Не Выборка.ОбменСВнешнейСистемой Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		ОтказПоСтрокеСценария = Ложь;
		
		ПередВыполнениемОбменов(Выборка.УзелИнформационнойБазы, ОтказПоСтрокеСценария);
		Если ОтказПоСтрокеСценария Тогда
			
			Отказ = Истина;
			Продолжить;
			
		КонецЕсли;
		
		Если Выборка.ОбменЧерезВнешнееСоединение Тогда
			
			ПроверитьВозможностьВнешнегоСоединения();
			
			КоличествоЭлементовВТранзакции = КоличествоЭлементовВТранзакцииВыполняемогоДействия(Выборка.ВыполняемоеДействие);
			
			ВыполнитьДействиеОбменаДляУзлаИнформационнойБазыПоВнешнемуСоединению(ОтказПоСтрокеСценария,
				Выборка.УзелИнформационнойБазы, Выборка.ВыполняемоеДействие, КоличествоЭлементовВТранзакции);
			
		ИначеЕсли Выборка.ОбменЧерезВебСервис Тогда
			
			ПараметрыОбмена = ПараметрыОбмена();
			ПараметрыОбмена.ДлительнаяОперацияРазрешена = Истина;
			ПараметрыОбмена.ИнтервалОжиданияНаСервере = 30;
			
			ОбменДаннымиВебСервис.ВыполнитьДействиеОбменаДляУзлаИнформационнойБазыЧерезWebСервис(ОтказПоСтрокеСценария,
				Выборка.УзелИнформационнойБазы, Выборка.ВыполняемоеДействие, ПараметрыОбмена);
			
		Иначе
			
			// ИНИЦИАЛИЗАЦИЯ ОБМЕНА ДАННЫМИ
			СтруктураНастроекОбмена = НастройкиОбменаДанными(Выборка.НастройкаВыполненияОбмена, Выборка.НомерСтроки);
			
			// Если настройка содержит ошибки, то обмен не производим; статус "Отменено".
			Если СтруктураНастроекОбмена.Отказ Тогда
				
				ОтказПоСтрокеСценария = Истина;
				
			Иначе
				
				СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено;
				
				// Добавляем в ЖР информацию о процессе обмена данными.
				СтрокаСообщения = НСтр("ru = 'Начало процесса обмена данными по настройке %1'", ОбщегоНазначения.КодОсновногоЯзыка());
				СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, СтруктураНастроекОбмена.НастройкаВыполненияОбменаНаименование);
				ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщения, СтруктураНастроекОбмена);
				
				// ОБМЕН ДАННЫМИ
				ВыполнитьОбменДаннымиЧерезФайловыйРесурс(СтруктураНастроекОбмена);
				
				ОтказПоСтрокеСценария = (РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена) <> Истина);
				
			КонецЕсли;
			
			// Фиксируем в ЖР лог по обмену данными.
			ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
			
		КонецЕсли;
		
		ПослеВыполненияОбменов(Выборка.УзелИнформационнойБазы, ОтказПоСтрокеСценария);
		
		Если ОтказПоСтрокеСценария Тогда
			
			Отказ = Истина;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Точка входа для выполнения обмена данными по сценарию обмена регламентным заданием.
//
// Параметры:
//  КодСценарияОбмена - Строка - код элемента справочника "Сценарии обменов данными", для которого будет выполнен обмен
//                               данными.
// 
Процедура ВыполнитьОбменДаннымиПоРегламентномуЗаданию(КодСценарияОбмена) Экспорт
	
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.СинхронизацияДанных);
	
	Если Не ЗначениеЗаполнено(КодСценарияОбмена) Тогда
		
		ВызватьИсключение НСтр("ru = 'Не задан сценарий обмена данными.'");
		
	КонецЕсли;
		
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Код", КодСценарияОбмена);
	
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	СценарииОбменовДанными.Ссылка КАК Ссылка
	|ИЗ
	|	Справочник.СценарииОбменовДанными КАК СценарииОбменовДанными
	|ГДЕ
	|		 СценарииОбменовДанными.Код = &Код
	|	И НЕ СценарииОбменовДанными.ПометкаУдаления
	|";
	
	РезультатЗапроса = Запрос.Выполнить();
	Если РезультатЗапроса.Пустой() Тогда
		
		СтрокаСообщения = НСтр("ru = 'Сценарий обмена данными с кодом %1 не найден.'");
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, КодСценарияОбмена);
		ВызватьИсключение СтрокаСообщения;
		
	КонецЕсли;
	
	Выборка = РезультатЗапроса.Выбрать();
	Если Выборка.Следующий() Тогда
		
		ВыполнитьОбменДаннымиПоСценариюОбменаДанными(Ложь, Выборка.Ссылка);
		
	КонецЕсли;
	
КонецПроцедуры

// Точка входа для выполнения итерации обмена данными - загрузки и выгрузки данных для узла плана обмена.
//
// Параметры:
//  УзелИнформационнойБазы - ПланОбменаСсылка - узел плана обмена, для которого выполняется итерация обмена данными.
//  ПараметрыОбмена - Структура:
//    * ВыполнятьЗагрузку - Булево - флаг необходимости выполнять загрузку данных.
//        Необязательный, значение по умолчанию Истина.
//    * ВыполнятьВыгрузку - Булево - флаг необходимости выполнять выгрузку данных.
//        Необязательный, значение по умолчанию Истина.
//    * ВидТранспортаСообщенийОбмена - ПеречислениеСсылка.ВидыТранспортаСообщенийОбмена - вид транспорта, 
//        который будет использоваться в процессе обмена данными. 
//        Если в РС значение не задано, то значение по умолчанию - Перечисления.ВидыТранспортаСообщенийОбмена.FILE.
//        Необязательный, значение по умолчанию Неопределено.
//    * ДлительнаяОперация - Булево - содержит сведения о том, является ли операция длительной.
//        Необязательный, значение по умолчанию Ложь.
//    * ИдентификаторОперации - Строка - содержит идентификатор длительной операции в виде строки.
//        Необязательный, значение по умолчанию пустая строка.
//    * ИдентификаторФайла - Строка - идентификатор файла сообщения в сервисе.
//        Необязательный, значение по умолчанию пустая строка.
//    * ДлительнаяОперацияРазрешена - Булево - содержит признак того, что длительная операция разрешена.
//        Необязательный, значение по умолчанию Ложь.
//    * ПараметрыАутентификации - Структура - содержит параметры аутентификации для обмена через Web-сервис.
//        Необязательный, значение по умолчанию Неопределено.
//    * ТолькоПараметры - Булево - содержит признак выборочной загрузки данных при обмене РИБ.
//        Необязательный, значение по умолчанию Ложь.
//  Отказ - Булево - флаг отказа; поднимается в случае возникновения ошибки при выполнении обмена.
//  ДополнительныеПараметры - Структура - зарезервировано для служебного использования.
// 
Процедура ВыполнитьОбменДаннымиДляУзлаИнформационнойБазы(УзелИнформационнойБазы, ПараметрыОбмена, Отказ, ДополнительныеПараметры = Неопределено) Экспорт
	
	ПередВыполнениемОбменов(УзелИнформационнойБазы, Отказ);
	
	Если Отказ = Истина Тогда
		
		Возврат;
		
	КонецЕсли;
	
	ДействиеЗагрузка = Перечисления.ДействияПриОбмене.ЗагрузкаДанных;
	ДействиеВыгрузка = Перечисления.ДействияПриОбмене.ВыгрузкаДанных;
	
	Если ДополнительныеПараметры = Неопределено Тогда
		
		ДополнительныеПараметры = Новый Структура;
		
	КонецЕсли;
	
	// Обмен через внешнее соединение.
	Если ПараметрыОбмена.ВидТранспортаСообщенийОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.COM Тогда
		
		ПроверитьВозможностьВнешнегоСоединения();
		
		Если ПараметрыОбмена.ВыполнятьЗагрузку Тогда
			ВыполнитьДействиеОбменаДляУзлаИнформационнойБазыПоВнешнемуСоединению(Отказ,
				УзелИнформационнойБазы, ДействиеЗагрузка, Неопределено);
		КонецЕсли;
		
		Если ПараметрыОбмена.ВыполнятьВыгрузку Тогда
			ВыполнитьДействиеОбменаДляУзлаИнформационнойБазыПоВнешнемуСоединению(Отказ,
				УзелИнформационнойБазы, ДействиеВыгрузка, Неопределено, ПараметрыОбмена.СообщениеДляСопоставленияДанных);
		КонецЕсли;
		
	ИначеЕсли ПараметрыОбмена.ВидТранспортаСообщенийОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.WS Тогда // Обмен через Web-сервис
		
		Если ПараметрыОбмена.ВыполнятьЗагрузку Тогда
			ОбменДаннымиВебСервис.ВыполнитьДействиеОбменаДляУзлаИнформационнойБазыЧерезWebСервис(Отказ,
				УзелИнформационнойБазы, ДействиеЗагрузка, ПараметрыОбмена);
		КонецЕсли;
		
		Если ПараметрыОбмена.ВыполнятьВыгрузку Тогда
			ОбменДаннымиВебСервис.ВыполнитьДействиеОбменаДляУзлаИнформационнойБазыЧерезWebСервис(Отказ,
				УзелИнформационнойБазы, ДействиеВыгрузка, ПараметрыОбмена);
		КонецЕсли;
			
	Иначе // Обмен через обычные каналы связи.
		
		ТолькоПараметры = ПараметрыОбмена.ТолькоПараметры;
		ВидТранспортаСообщенийОбмена = ПараметрыОбмена.ВидТранспортаСообщенийОбмена;
		
		Если ПараметрыОбмена.ВыполнятьЗагрузку Тогда
			ВыполнитьДействиеОбменаДляУзлаИнформационнойБазы(Отказ, УзелИнформационнойБазы,
				ДействиеЗагрузка, ВидТранспортаСообщенийОбмена, ТолькоПараметры, ДополнительныеПараметры);
		КонецЕсли;
		
		Если ПараметрыОбмена.ВыполнятьВыгрузку Тогда
			ВыполнитьДействиеОбменаДляУзлаИнформационнойБазы(Отказ, УзелИнформационнойБазы,
				ДействиеВыгрузка, ВидТранспортаСообщенийОбмена, ТолькоПараметры, ДополнительныеПараметры);
		КонецЕсли;
		
	КонецЕсли;
	
	ПослеВыполненияОбменов(УзелИнформационнойБазы, Отказ);
	
КонецПроцедуры

#КонецОбласти

#Область ДляРаботыЧерезВнешнееСоединение_СлужебныеПроцедурыИФункции

Процедура ВыполнитьВыгрузкуДляУзлаИнформационнойБазыВоВременноеХранилище(Знач ИмяПланаОбмена, Знач КодУзлаИнформационнойБазы, Адрес) Экспорт
	
	ПолноеИмяФайлаСообщенияОбмена = ПолучитьИмяВременногоФайла("xml");
	
	ПараметрыОбменаДанными = ПараметрыОбменаДаннымиЧерезФайлИлиСтроку();
	
	ПараметрыОбменаДанными.ПолноеИмяФайлаСообщенияОбмена = ПолноеИмяФайлаСообщенияОбмена;
	ПараметрыОбменаДанными.ДействиеПриОбмене             = Перечисления.ДействияПриОбмене.ВыгрузкаДанных;
	ПараметрыОбменаДанными.ИмяПланаОбмена                = ИмяПланаОбмена;
	ПараметрыОбменаДанными.КодУзлаИнформационнойБазы     = КодУзлаИнформационнойБазы;
	
	ВыполнитьОбменДаннымиДляУзлаИнформационнойБазыЧерезФайлИлиСтроку(ПараметрыОбменаДанными);
	
	Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ПолноеИмяФайлаСообщенияОбмена));
	
	УдалитьФайлы(ПолноеИмяФайлаСообщенияОбмена);
	
КонецПроцедуры

Процедура ВыполнитьВыгрузкуДляУзлаИнформационнойБазыЧерезФайл(Знач ИмяПланаОбмена,
	Знач КодУзлаИнформационнойБазы,
	Знач ПолноеИмяФайлаСообщенияОбмена) Экспорт
	
	ПараметрыОбменаДанными = ПараметрыОбменаДаннымиЧерезФайлИлиСтроку();
	
	ПараметрыОбменаДанными.ПолноеИмяФайлаСообщенияОбмена = ПолноеИмяФайлаСообщенияОбмена;
	ПараметрыОбменаДанными.ДействиеПриОбмене             = Перечисления.ДействияПриОбмене.ВыгрузкаДанных;
	ПараметрыОбменаДанными.ИмяПланаОбмена                = ИмяПланаОбмена;
	ПараметрыОбменаДанными.КодУзлаИнформационнойБазы     = КодУзлаИнформационнойБазы;
	
	ВыполнитьОбменДаннымиДляУзлаИнформационнойБазыЧерезФайлИлиСтроку(ПараметрыОбменаДанными);
	
КонецПроцедуры

Процедура ВыполнитьВыгрузкуДляУзлаИнформационнойБазыЧерезСтроку(Знач ИмяПланаОбмена, Знач КодУзлаИнформационнойБазы, СообщениеОбмена) Экспорт
	
	ПараметрыОбменаДанными = ПараметрыОбменаДаннымиЧерезФайлИлиСтроку();
	
	ПараметрыОбменаДанными.ДействиеПриОбмене             = Перечисления.ДействияПриОбмене.ВыгрузкаДанных;
	ПараметрыОбменаДанными.ИмяПланаОбмена                = ИмяПланаОбмена;
	ПараметрыОбменаДанными.КодУзлаИнформационнойБазы     = КодУзлаИнформационнойБазы;
	ПараметрыОбменаДанными.СообщениеОбмена               = СообщениеОбмена;
	
	ВыполнитьОбменДаннымиДляУзлаИнформационнойБазыЧерезФайлИлиСтроку(ПараметрыОбменаДанными);
	
	СообщениеОбмена = ПараметрыОбменаДанными.СообщениеОбмена;
	
КонецПроцедуры

Процедура ВыполнитьЗагрузкуДляУзлаИнформационнойБазыЧерезСтроку(Знач ИмяПланаОбмена, Знач КодУзлаИнформационнойБазы, СообщениеОбмена) Экспорт
	
	ПараметрыОбменаДанными = ПараметрыОбменаДаннымиЧерезФайлИлиСтроку();
	
	ПараметрыОбменаДанными.ДействиеПриОбмене             = Перечисления.ДействияПриОбмене.ЗагрузкаДанных;
	ПараметрыОбменаДанными.ИмяПланаОбмена                = ИмяПланаОбмена;
	ПараметрыОбменаДанными.КодУзлаИнформационнойБазы     = КодУзлаИнформационнойБазы;
	ПараметрыОбменаДанными.СообщениеОбмена               = СообщениеОбмена;
	
	ВыполнитьОбменДаннымиДляУзлаИнформационнойБазыЧерезФайлИлиСтроку(ПараметрыОбменаДанными);
	
	СообщениеОбмена = ПараметрыОбменаДанными.СообщениеОбмена;
	
КонецПроцедуры

Процедура ЗафиксироватьЗавершениеОбменаЧерезВнешнееСоединение(СтруктураНастроекОбмена) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
	
КонецПроцедуры

Функция СтруктураНастроекОбменаЧерезВнешнееСоединение(Структура) Экспорт
	
	ПроверитьИспользованиеОбменаДанными();
	
	УстановитьПривилегированныйРежим(Истина);
	
	УзелИнформационнойБазы = ПланыОбмена[Структура.ИмяПланаОбмена].НайтиПоКоду(Структура.ТекущийУзелПланаОбменаКод);
	
	ДействиеПриОбмене = Перечисления.ДействияПриОбмене[Структура.ДействиеПриОбменеСтрокой];
	
	СтруктураНастроекОбменаВнешнееСоединение = Новый Структура;
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ИмяПланаОбмена",                   Структура.ИмяПланаОбмена);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("РежимОтладки",                     Структура.РежимОтладки);
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("УзелИнформационнойБазы",             УзелИнформационнойБазы);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("УзелИнформационнойБазыНаименование", Строка(УзелИнформационнойБазы));
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("КлючСообщенияЖурналаРегистрации",  КлючСообщенияЖурналаРегистрации(УзелИнформационнойБазы, ДействиеПриОбмене));
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("РезультатВыполненияОбмена",        Неопределено);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("РезультатВыполненияОбменаСтрокой", "");
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ДействиеПриОбмене", ДействиеПриОбмене);
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ОтладкаОбработчиковВыгрузки ", Ложь);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ОтладкаОбработчиковЗагрузки", Ложь);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ИмяФайлаВнешнейОбработкиОтладкиВыгрузки", "");
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ИмяФайлаВнешнейОбработкиОтладкиЗагрузки", "");
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("РежимПротоколированияОбменаДанными", Ложь);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ИмяФайлаПротоколаОбмена", "");
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ПродолжитьПриОшибке", Ложь);
	
	УстановитьНастройкиРежимаОтладкиДляСтруктуры(СтруктураНастроекОбменаВнешнееСоединение, Истина);
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("КоличествоОбъектовОбработано", 0);
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ДатаНачала",    Неопределено);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ДатаОкончания", Неопределено);
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("СообщениеПриОбмене",      "");
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("СтрокаСообщенияОбОшибке", "");
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("КоличествоЭлементовВТранзакции", Структура.КоличествоЭлементовВТранзакции);
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ЭтоОбменВРИБ", Ложь);
	
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("НастройкаСинхронизацииДанныхЗавершена",     Ложь);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ПолученоСообщениеДляСопоставленияДанных",   Ложь);
	СтруктураНастроекОбменаВнешнееСоединение.Вставить("ПоддерживаетсяСопоставлениеДанных",         Истина);
	
	Если ЗначениеЗаполнено(УзелИнформационнойБазы) Тогда
		СтруктураНастроекОбменаВнешнееСоединение.НастройкаСинхронизацииДанныхЗавершена   = НастройкаСинхронизацииЗавершена(УзелИнформационнойБазы);
		СтруктураНастроекОбменаВнешнееСоединение.ПолученоСообщениеДляСопоставленияДанных = ПолученоСообщениеСДаннымиДляСопоставления(УзелИнформационнойБазы);
		СтруктураНастроекОбменаВнешнееСоединение.ПоддерживаетсяСопоставлениеДанных = ЗначениеНастройкиПланаОбмена(Структура.ИмяПланаОбмена,
			"ПоддерживаетсяСопоставлениеДанных", СохраненныйВариантНастройкиУзлаПланаОбмена(УзелИнформационнойБазы));
	КонецЕсли;
	
	Возврат СтруктураНастроекОбменаВнешнееСоединение;
КонецФункции

Функция ПолучитьПравилаКонвертацииОбъектовЧерезВнешнееСоединение(ИмяПланаОбмена, ПолучатьПравилаКорреспондента = Ложь) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат РегистрыСведений.ПравилаДляОбменаДанными.ЗачитанныеПравилаКонвертацииОбъектов(ИмяПланаОбмена, ПолучатьПравилаКорреспондента);
	
КонецФункции

Процедура ВыполнитьОбменДаннымиСВнешнейСистемойЗагрузкаДанных(СтруктураНастроекОбмена)
	
	ИмяВременногоКаталога = СоздатьВременныйКаталогСообщенийОбмена();
	
	ИмяФайлаСообщения = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
		ИмяВременногоКаталога, УникальноеИмяФайлаСообщенияОбмена());
		
	ОбработкаТранспортаСообщенийОбмена = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена;
	
	СообщениеПолучено = Ложь;
	Попытка
		СообщениеПолучено = ОбработкаТранспортаСообщенийОбмена.ПолучитьСообщение(ИмяФайлаСообщения);
	Исключение
		Информация = ИнформацияОбОшибке();
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения;
		ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация), СтруктураНастроекОбмена, Истина);
	КонецПопытки;
	
	СообщениеОбработано = Ложь;
	ВыполнитьОбработчикПослеЗагрузки = Ложь;
	
	Если СообщениеПолучено
		И СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено Тогда
		
		ВыполнитьОбработчикПослеЗагрузки = Истина;
		
		ПрочитатьСообщениеСИзменениямиДляУзла(СтруктураНастроекОбмена, ИмяФайлаСообщения);
		
		СообщениеОбработано = РезультатВыполненияОбменаВыполнено(СтруктураНастроекОбмена.РезультатВыполненияОбмена);
		
	КонецЕсли;
	
	Попытка
		УдалитьФайлы(ИмяВременногоКаталога);
	Исключение
		ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация), СтруктураНастроекОбмена);
	КонецПопытки;
	
	НастройкаЗавершена = НастройкаСинхронизацииЗавершена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	
	Если ВыполнитьОбработчикПослеЗагрузки Тогда
		ЕстьСледующееСообщение = Ложь;
		Попытка
			ОбработкаТранспортаСообщенийОбмена.ПослеОбработкиПолученногоСообщения(СообщениеОбработано, ЕстьСледующееСообщение);
		Исключение
			Информация = ИнформацияОбОшибке();
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения;
			ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация), СтруктураНастроекОбмена, Истина);
			ЕстьСледующееСообщение = Ложь;
		КонецПопытки;
		
		Если СообщениеОбработано
			И Не НастройкаЗавершена Тогда
			
			ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
			
			Если ЕстьАлгоритмМенеджераПланаОбмена("ПередНастройкойСинхронизацииДанных", ИмяПланаОбмена) Тогда
		
				Контекст = Новый Структура;
				Контекст.Вставить("Корреспондент",          СтруктураНастроекОбмена.УзелИнформационнойБазы);
				Контекст.Вставить("ИдентификаторНастройки", СохраненныйВариантНастройкиУзлаПланаОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы));
				Контекст.Вставить("НачальнаяНастройка",     Не НастройкаЗавершена);
				
				ИмяФормыПомощника  = "";
				
				ПланыОбмена[ИмяПланаОбмена].ПередНастройкойСинхронизацииДанных(Контекст, НастройкаЗавершена, ИмяФормыПомощника);
				
				Если НастройкаЗавершена Тогда
					ЗавершитьНастройкуСинхронизацииДанных(СтруктураНастроекОбмена.УзелИнформационнойБазы);
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
		
		Если ЕстьСледующееСообщение И НастройкаЗавершена Тогда
			СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено;
			ВыполнитьОбменДаннымиСВнешнейСистемойЗагрузкаДанных(СтруктураНастроекОбмена);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьОбменДаннымиСВнешнейСистемойВыгрузкаНастроекXDTO(СтруктураНастроекОбмена)
	
	ОбработкаТранспортаСообщенийОбмена = СтруктураНастроекОбмена.ОбработкаТранспортаСообщенийОбмена;
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
		
	НастройкиXDTO = Новый Структура;
	НастройкиXDTO.Вставить("ФорматОбмена",
		ЗначениеНастройкиПланаОбмена(ИмяПланаОбмена, "ФорматОбмена"));
	НастройкиXDTO.Вставить("ПоддерживаемыеВерсии",
		ОбменДаннымиXDTOСервер.ВерсииФорматаОбменаМассив(СтруктураНастроекОбмена.УзелИнформационнойБазы));
	НастройкиXDTO.Вставить("ПоддерживаемыеОбъекты",
		ОбменДаннымиXDTOСервер.ПоддерживаемыеОбъектыФормата(ИмяПланаОбмена, , СтруктураНастроекОбмена.УзелИнформационнойБазы));
	
	Попытка
		ОбработкаТранспортаСообщенийОбмена.ОтправитьНастройкиXDTO(НастройкиXDTO);
	Исключение
		Информация = ИнформацияОбОшибке();
		СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения;
		ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация), СтруктураНастроекОбмена, Истина);
	КонецПопытки;
	
КонецПроцедуры

Процедура ПередЧтениемСообщенияОбмена(Знач Получатель, СообщениеОбмена, СтандартнаяОбработка) Экспорт
	
	Если ЭтоПодчиненныйУзелРИБ()
		И ТипЗнч(ГлавныйУзел()) = ТипЗнч(Получатель) Тогда
		
		СохраненноеСообщениеОбмена = СообщениеОбменаДаннымиИзГлавногоУзла();
		
		Если ТипЗнч(СохраненноеСообщениеОбмена) = Тип("ДвоичныеДанные") Тогда
			// Приведение к новому формату хранения и повторное зачитывание
			// значения константы СообщениеОбменаДаннымиИзГлавногоУзла.
			УстановитьСообщениеОбменаДаннымиИзГлавногоУзла(СохраненноеСообщениеОбмена, Получатель);
			СохраненноеСообщениеОбмена = СообщениеОбменаДаннымиИзГлавногоУзла();
		КонецЕсли;
		
		Если ТипЗнч(СохраненноеСообщениеОбмена) = Тип("Структура") Тогда
			
			СтандартнаяОбработка = Ложь;
			
			СообщениеОбмена = СохраненноеСообщениеОбмена.ПутьКФайлу;
			
			ЗаписатьСобытиеПолученияДанных(Получатель, НСтр("ru = 'Сообщение обмена получено из кэша.'"));
			
			УстановитьПривилегированныйРежим(Истина);
			УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("СообщениеПолученоИзКэша", Истина);
			УстановитьПривилегированныйРежим(Ложь);
			
		Иначе
			УстановитьПривилегированныйРежим(Истина);
			УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("СообщениеПолученоИзКэша", Ложь);
			УстановитьПривилегированныйРежим(Ложь);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ПослеЧтенияСообщенияОбмена(Знач Получатель, Знач СообщениеОбмена, Знач СообщениеПрочитано,
		СтандартнаяОбработка, Знач УдалитьСообщение = Истина) Экспорт
	
	Если ОбменДаннымиСлужебный.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРасширений") Тогда
		Возврат;
	КонецЕсли;
	
	Если ЭтоПодчиненныйУзелРИБ()
		И ТипЗнч(ГлавныйУзел()) = ТипЗнч(Получатель) Тогда
		
		Если Не СообщениеПрочитано
		   И ОбменДаннымиСлужебный.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("СообщениеПолученоИзКэша") Тогда
			// Не удалось прочитать сообщение, полученное из кэша - требуется очистка кэша.
			ОчиститьСообщениеОбменаДаннымиИзГлавногоУзла();
			Возврат;
		КонецЕсли;
		
		ОбновитьСообщениеВКэше = Ложь;
		
		Если КонфигурацияИзменена() ИЛИ ОбменДаннымиСлужебный.ЗагрузитьРасширенияИзменяющиеСтруктуруДанных() Тогда
			
			// Т.к. конфигурация может быть изменена повторно, требуется
			// обновить кэш, если он содержит устаревшее сообщение,
			// а не только при первой загрузке изменений конфигурации.
			ОбновитьСообщениеВКэше = Истина;
			
			Если Не СообщениеПрочитано Тогда
				
				Если НЕ Константы.ЗагрузитьСообщениеОбменаДанными.Получить() Тогда
					Константы.ЗагрузитьСообщениеОбменаДанными.Установить(Истина);
				КонецЕсли;
				
			КонецЕсли;
			
		Иначе
			
			Если УдалитьСообщение Тогда
				
				ОчиститьСообщениеОбменаДаннымиИзГлавногоУзла();
				Если Константы.ЗагрузитьСообщениеОбменаДанными.Получить() Тогда
					Константы.ЗагрузитьСообщениеОбменаДанными.Установить(Ложь);
				КонецЕсли;
				
			Иначе
				// Т.к. чтение сообщение обмена может быть без загрузки метаданных,
				// то нужно сохранить сообщение обмена после чтения параметров работы программы,
				// чтобы не загружать его повторно для основного чтения.
				ОбновитьСообщениеВКэше = Истина;
			КонецЕсли;
			
		КонецЕсли;
		
		Если ОбновитьСообщениеВКэше Тогда
			
			СтароеСообщение = СообщениеОбменаДаннымиИзГлавногоУзла();
			
			ОбновитьКэш = Ложь;
			НовоеСообщение = Новый ДвоичныеДанные(СообщениеОбмена);
			
			ТипСтруктура = ТипЗнч(СтароеСообщение) = Тип("Структура");
			
			Если ТипСтруктура Или ТипЗнч(СтароеСообщение) = Тип("ДвоичныеДанные") Тогда
				
				Если ТипСтруктура Тогда
					СтароеСообщение = Новый ДвоичныеДанные(СтароеСообщение.ПутьКФайлу);
				КонецЕсли;
				
				Если СтароеСообщение.Размер() <> НовоеСообщение.Размер() Тогда
					ОбновитьКэш = Истина;
				ИначеЕсли НовоеСообщение <> СтароеСообщение Тогда
					ОбновитьКэш = Истина;
				КонецЕсли;
				
			Иначе
				
				ОбновитьКэш = Истина;
				
			КонецЕсли;
			
			Если ОбновитьКэш Тогда
				УстановитьСообщениеОбменаДаннымиИзГлавногоУзла(НовоеСообщение, Получатель);
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Если СообщениеПрочитано И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		РегистрыСведений.ОбработчикиСобытийСинхронизацииДанных.ВыполнитьОбработчики(Получатель, "ПослеПолученияДанных");
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ИнициализацияСтруктурыНастроекОбмена_СлужебныеПроцедурыИФункции

// Выполняет инициализацию подсистемы обмена данными для выполнения процесса обмена.
//
// Параметры:
// 
// Возвращаемое значение:
//  Структура - структура со всеми необходимыми данными и объектами для выполнения обмена.
//
Функция НастройкиОбменаДляВнешнегоСоединения(УзелИнформационнойБазы, ДействиеПриОбмене, КоличествоЭлементовВТранзакции)
	
	// Возвращаемое значение функции.
	СтруктураНастроекОбмена = СтруктураНастроекОбменаБазовая();
	
	СтруктураНастроекОбмена.УзелИнформационнойБазы = УзелИнформационнойБазы;
	СтруктураНастроекОбмена.ДействиеПриОбмене      = ДействиеПриОбмене;
	СтруктураНастроекОбмена.ЭтоОбменВРИБ           = ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(УзелИнформационнойБазы);
	
	СтруктураСвойств = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(СтруктураНастроекОбмена.УзелИнформационнойБазы, "Код, Наименование");
	
	СтруктураНастроекОбмена.УзелИнформационнойБазыКод = ИдентификаторУзлаКорреспондентаДляОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураНастроекОбмена.УзелИнформационнойБазыНаименование = СтруктураСвойств.Наименование;
	
	СтруктураНастроекОбмена.НастройкиТранспорта = РегистрыСведений.НастройкиТранспортаОбменаДанными.НастройкиТранспорта(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	
	Если КоличествоЭлементовВТранзакции = Неопределено Тогда
		КоличествоЭлементовВТранзакции = КоличествоЭлементовВТранзакцииВыполняемогоДействия(ДействиеПриОбмене);
	КонецЕсли;
	
	СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции = КоличествоЭлементовВТранзакции;
	
	// ВЫЧИСЛЯЕМЫЕ ЗНАЧЕНИЯ
	СтруктураНастроекОбмена.ПроизводитьЗагрузкуДанных = (СтруктураНастроекОбмена.ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ЗагрузкаДанных);
	СтруктураНастроекОбмена.ПроизводитьВыгрузкуДанных = (СтруктураНастроекОбмена.ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ВыгрузкаДанных);
	
	СтруктураНастроекОбмена.ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураНастроекОбмена.ИмяПланаОбменаКорреспондента =
		ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбменаКорреспондента(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	
	СтруктураНастроекОбмена.ТекущийУзелПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьЭтотУзелПланаОбмена(СтруктураНастроекОбмена.ИмяПланаОбмена);
	СтруктураНастроекОбмена.ТекущийУзелПланаОбменаКод = ИдентификаторЭтогоУзлаДляОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	
	// Получаем ключ сообщения для ЖР.
	СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации = КлючСообщенияЖурналаРегистрации(СтруктураНастроекОбмена.УзелИнформационнойБазы, СтруктураНастроекОбмена.ДействиеПриОбмене);
	
	СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.COM;
	
	УстановитьНастройкиРежимаОтладкиДляСтруктуры(СтруктураНастроекОбмена);
	
	// Проверяем структуру настроек на валидность значений для выполнения обмена. Ошибки фиксируем в ЖР.
	ВыполнитьПроверкуСтруктурыОбменаНаВалидность(СтруктураНастроекОбмена);
	
	// Если настройки содержат ошибки, то выходим.
	Если СтруктураНастроекОбмена.Отказ Тогда
		Возврат СтруктураНастроекОбмена;
	КонецЕсли;
	
	// Инициализируем обработку обмена данными.
	ВыполнитьИнициализациюОбработкиОбменаПоПравиламКонвертации(СтруктураНастроекОбмена);
	
	Возврат СтруктураНастроекОбмена;
КонецФункции

// Выполняет инициализацию подсистемы обмена данными для выполнения процесса обмена.
//
// Параметры:
// 
// Возвращаемое значение:
//  СтруктураНастроекОбмена - Структура - структура со всеми необходимыми данными и объектами для выполнения обмена.
//
Функция НастройкиОбменаДанными(НастройкаВыполненияОбмена, НомерСтроки)
	
	// Возвращаемое значение функции.
	СтруктураНастроекОбмена = СтруктураНастроекОбменаБазовая();
	
	ВыполнитьИнициализациюСтруктурыНастроекОбмена(СтруктураНастроекОбмена, НастройкаВыполненияОбмена, НомерСтроки);
	
	Если СтруктураНастроекОбмена.Отказ Тогда
		Возврат СтруктураНастроекОбмена;
	КонецЕсли;
	
	УстановитьНастройкиРежимаОтладкиДляСтруктуры(СтруктураНастроекОбмена);
	
	// Проверяем структуру настроек на валидность значений для выполнения обмена. Ошибки фиксируем в ЖР.
	ВыполнитьПроверкуСтруктурыОбменаНаВалидность(СтруктураНастроекОбмена);
	
	// Если настройки содержат ошибки, то выходим.
	Если СтруктураНастроекОбмена.Отказ Тогда
		Возврат СтруктураНастроекОбмена;
	КонецЕсли;
	
	// Инициализируем обработку транспорта сообщений обмена.
	ВыполнитьИнициализациюОбработкиТранспортаСообщенийОбмена(СтруктураНастроекОбмена);
	
	// Инициализируем обработку обмена данными.
	Если СтруктураНастроекОбмена.ЭтоОбменВРИБ Тогда
		
		ВыполнитьИнициализациюОбработкиОбмена(СтруктураНастроекОбмена);
		
	ИначеЕсли СтруктураНастроекОбмена.ОбменПоПравиламКонвертацииОбъектов Тогда
		
		ВыполнитьИнициализациюОбработкиОбменаПоПравиламКонвертации(СтруктураНастроекОбмена);
		
	КонецЕсли;
	
	Возврат СтруктураНастроекОбмена;
КонецФункции

// Получает структуру настроек транспорта для выполнения обмена данными.
//
Функция НастройкиТранспортаОбмена(УзелИнформационнойБазы, ВидТранспортаСообщенийОбмена) Экспорт
	
	// Возвращаемое значение функции.
	СтруктураНастроекОбмена = СтруктураНастроекОбменаБазовая();
	
	СтруктураНастроекОбмена.УзелИнформационнойБазы = УзелИнформационнойБазы;
	СтруктураНастроекОбмена.ДействиеПриОбмене      = Перечисления.ДействияПриОбмене.ЗагрузкаДанных;
	СтруктураНастроекОбмена.ВидТранспортаОбмена    = ВидТранспортаСообщенийОбмена;
	
	ВыполнитьИнициализациюСтруктурыНастроекОбменаДляУзлаИнформационнойБазы(СтруктураНастроекОбмена, Истина);
	
	// Проверяем структуру настроек на валидность значений для выполнения обмена. Ошибки фиксируем в ЖР.
	ВыполнитьПроверкуСтруктурыОбменаНаВалидность(СтруктураНастроекОбмена);
	
	// Если настройки содержат ошибки, то выходим.
	Если СтруктураНастроекОбмена.Отказ Тогда
		Возврат СтруктураНастроекОбмена;
	КонецЕсли;
	
	// Инициализируем обработку транспорта сообщений обмена.
	ВыполнитьИнициализациюОбработкиТранспортаСообщенийОбмена(СтруктураНастроекОбмена);
	
	Возврат СтруктураНастроекОбмена;
КонецФункции

// Структура настроек обмена для сеанса интерактивной загрузки.
// 
// Параметры:
//  УзелИнформационнойБазы - ПланОбменаСсылка - узел информационной базы.
//  ИмяФайлаСообщенияОбмена - Строка -  имя файла сообщения обмена.
// 
// Возвращаемое значение:
//   см. СтруктураНастроекОбменаБазовая.
//
Функция СтруктураНастроекОбменаДляСеансаИнтерактивнойЗагрузки(Знач УзелИнформационнойБазы, Знач ИмяФайлаСообщенияОбмена) Экспорт
	
	Возврат ОбменДаннымиПовтИсп.СтруктураНастроекОбменаДляСеансаИнтерактивнойЗагрузки(УзелИнформационнойБазы, ИмяФайлаСообщенияОбмена);
	
КонецФункции

Процедура ВыполнитьИнициализациюСтруктурыНастроекОбмена(СтруктураНастроекОбмена, НастройкаВыполненияОбмена, НомерСтроки)
	
	ТекстЗапроса = "
	|ВЫБРАТЬ
	|	НастройкиВыполненияОбменаНастройкиОбмена.УзелИнформационнойБазы         КАК УзелИнформационнойБазы,
	|	НастройкиВыполненияОбменаНастройкиОбмена.УзелИнформационнойБазы.Код     КАК УзелИнформационнойБазыКод,
	|	НастройкиВыполненияОбменаНастройкиОбмена.ВидТранспортаОбмена            КАК ВидТранспортаОбмена,
	|	НастройкиВыполненияОбменаНастройкиОбмена.ВыполняемоеДействие            КАК ДействиеПриОбмене,
	|	НастройкиВыполненияОбменаНастройкиОбмена.Ссылка                         КАК НастройкаВыполненияОбмена,
	|	НастройкиВыполненияОбменаНастройкиОбмена.Ссылка.Наименование            КАК НастройкаВыполненияОбменаНаименование,
	|	ВЫБОР
	|		КОГДА НастройкиВыполненияОбменаНастройкиОбмена.ВыполняемоеДействие = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных) ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ                                                                   КАК ПроизводитьЗагрузкуДанных,
	|	ВЫБОР
	|		КОГДА НастройкиВыполненияОбменаНастройкиОбмена.ВыполняемоеДействие = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных) ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ                                                                   КАК ПроизводитьВыгрузкуДанных
	|ИЗ
	|	Справочник.СценарииОбменовДанными.НастройкиОбмена КАК НастройкиВыполненияОбменаНастройкиОбмена
	|ГДЕ
	|	  НастройкиВыполненияОбменаНастройкиОбмена.Ссылка      = &НастройкаВыполненияОбмена
	|	И НастройкиВыполненияОбменаНастройкиОбмена.НомерСтроки = &НомерСтроки
	|";
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("НастройкаВыполненияОбмена", НастройкаВыполненияОбмена);
	Запрос.УстановитьПараметр("НомерСтроки",               НомерСтроки);
	
	Выборка = Запрос.Выполнить().Выбрать();
	Выборка.Следующий();
	
	// Заполняем значения свойств структуры.
	ЗаполнитьЗначенияСвойств(СтруктураНастроекОбмена, Выборка);
	
	СтруктураНастроекОбмена.ЭтоОбменВРИБ = ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	
	СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации = НСтр("ru = 'Обмен данными'");
	
	// Выполняем проверку задания основных полей структуры настроек обмена.
	ВыполнитьПроверкуОсновныхПолейСтруктурыНастроекОбмена(СтруктураНастроекОбмена);
	
	Если СтруктураНастроекОбмена.Отказ Тогда
		Возврат;
	КонецЕсли;
	
	//
	СтруктураНастроекОбмена.ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураНастроекОбмена.ОбменПоПравиламКонвертацииОбъектов = ОбменДаннымиПовтИсп.ЭтоУзелУниверсальногоОбменаДанными(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	
	СтруктураНастроекОбмена.ТекущийУзелПланаОбмена    = ПланыОбмена[СтруктураНастроекОбмена.ИмяПланаОбмена].ЭтотУзел();
	СтруктураНастроекОбмена.ТекущийУзелПланаОбменаКод = СтруктураНастроекОбмена.ТекущийУзелПланаОбмена.Код;
	
	СтруктураНастроекОбмена.ИмяОбработкиТранспортаСообщенийОбмена = ИмяОбработкиТранспортаСообщенийОбмена(СтруктураНастроекОбмена.ВидТранспортаОбмена);
	
	// Получаем ключ сообщения для ЖР.
	СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации = КлючСообщенияЖурналаРегистрации(СтруктураНастроекОбмена.УзелИнформационнойБазы, СтруктураНастроекОбмена.ДействиеПриОбмене);
	
	Если ОбменДаннымиПовтИсп.ЭтоУзелОбменаСообщениями(СтруктураНастроекОбмена.УзелИнформационнойБазы) Тогда
		МодульНастройкиТранспортаОбменаСообщениями = ОбщегоНазначения.ОбщийМодуль("РегистрыСведений.НастройкиТранспортаОбменаСообщениями");
		СтруктураНастроекОбмена.НастройкиТранспорта = МодульНастройкиТранспортаОбменаСообщениями.НастройкиТранспортаWS(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	Иначе
		СтруктураНастроекОбмена.НастройкиТранспорта = РегистрыСведений.НастройкиТранспортаОбменаДанными.НастройкиТранспорта(СтруктураНастроекОбмена.УзелИнформационнойБазы, СтруктураНастроекОбмена.ВидТранспортаОбмена);
	КонецЕсли;
	
	СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции = КоличествоЭлементовВТранзакцииВыполняемогоДействия(СтруктураНастроекОбмена.ДействиеПриОбмене);
	
КонецПроцедуры

Процедура ВыполнитьИнициализациюСтруктурыНастроекОбменаДляУзлаИнформационнойБазы(
		СтруктураНастроекОбмена,
		ИспользоватьНастройкиТранспорта)
	
	СтруктураСвойств = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(СтруктураНастроекОбмена.УзелИнформационнойБазы, "Код, Наименование");
	
	СтруктураНастроекОбмена.УзелИнформационнойБазыКод = ИдентификаторУзлаКорреспондентаДляОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураНастроекОбмена.УзелИнформационнойБазыНаименование = СтруктураСвойств.Наименование;
	
	// Получаем настройки транспорта обмена.
	Если ОбменДаннымиПовтИсп.ЭтоУзелОбменаСообщениями(СтруктураНастроекОбмена.УзелИнформационнойБазы) Тогда
		МодульНастройкиТранспортаОбменаСообщениями = ОбщегоНазначения.ОбщийМодуль("РегистрыСведений.НастройкиТранспортаОбменаСообщениями");
		СтруктураНастроекОбмена.НастройкиТранспорта = МодульНастройкиТранспортаОбменаСообщениями.НастройкиТранспортаWS(
			СтруктураНастроекОбмена.УзелИнформационнойБазы);
	Иначе
		СтруктураНастроекОбмена.НастройкиТранспорта = РегистрыСведений.НастройкиТранспортаОбменаДанными.НастройкиТранспорта(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	КонецЕсли;
	
	Если СтруктураНастроекОбмена.НастройкиТранспорта <> Неопределено Тогда
		
		Если ИспользоватьНастройкиТранспорта Тогда
			
			// Если не указан вид транспорта, то используем значение по умолчанию.
			Если СтруктураНастроекОбмена.ВидТранспортаОбмена = Неопределено Тогда
				СтруктураНастроекОбмена.ВидТранспортаОбмена = СтруктураНастроекОбмена.НастройкиТранспорта.ВидТранспортаСообщенийОбменаПоУмолчанию;
			КонецЕсли;
			
			// Если вид транспорта не задан, то используем транспорт FILE.
			Если Не ЗначениеЗаполнено(СтруктураНастроекОбмена.ВидТранспортаОбмена) Тогда
				
				СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.FILE;
				
			КонецЕсли;
			
			СтруктураНастроекОбмена.ИмяОбработкиТранспортаСообщенийОбмена = ИмяОбработкиТранспортаСообщенийОбмена(СтруктураНастроекОбмена.ВидТранспортаОбмена);
			
		КонецЕсли;
		
		СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции = КоличествоЭлементовВТранзакцииВыполняемогоДействия(СтруктураНастроекОбмена.ДействиеПриОбмене);
		
		Если СтруктураНастроекОбмена.НастройкиТранспорта.Свойство("WSИспользоватьПередачуБольшогоОбъемаДанных") Тогда
			СтруктураНастроекОбмена.ИспользоватьПередачуБольшогоОбъемаДанных = СтруктураНастроекОбмена.НастройкиТранспорта.WSИспользоватьПередачуБольшогоОбъемаДанных;
		КонецЕсли;
		
	КонецЕсли;
	
	// ЗНАЧЕНИЯ ПО УМОЛЧАНИЮ
	СтруктураНастроекОбмена.НастройкаВыполненияОбмена             = Неопределено;
	СтруктураНастроекОбмена.НастройкаВыполненияОбменаНаименование = "";
	
	// ВЫЧИСЛЯЕМЫЕ ЗНАЧЕНИЯ
	СтруктураНастроекОбмена.ПроизводитьЗагрузкуДанных = (СтруктураНастроекОбмена.ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ЗагрузкаДанных);
	СтруктураНастроекОбмена.ПроизводитьВыгрузкуДанных = (СтруктураНастроекОбмена.ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ВыгрузкаДанных);
	
	СтруктураНастроекОбмена.ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураНастроекОбмена.ИмяПланаОбменаКорреспондента = 
		ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбменаКорреспондента(СтруктураНастроекОбмена.УзелИнформационнойБазы);
		
	СтруктураНастроекОбмена.ОбменПоПравиламКонвертацииОбъектов  = ОбменДаннымиПовтИсп.ЭтоУзелУниверсальногоОбменаДанными(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураНастроекОбмена.НаличиеПравилКонвертацииОбязательно = ЗначениеНастройкиПланаОбмена(СтруктураНастроекОбмена.ИмяПланаОбмена, "НаличиеПравилКонвертацииОбязательно");
	
	СтруктураНастроекОбмена.ТекущийУзелПланаОбмена    = ПланыОбмена[СтруктураНастроекОбмена.ИмяПланаОбмена].ЭтотУзел();
	СтруктураНастроекОбмена.ТекущийУзелПланаОбменаКод = ИдентификаторЭтогоУзлаДляОбмена(СтруктураНастроекОбмена.УзелИнформационнойБазы);
	
	// Получаем ключ сообщения для ЖР.
	СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации = КлючСообщенияЖурналаРегистрации(СтруктураНастроекОбмена.УзелИнформационнойБазы, СтруктураНастроекОбмена.ДействиеПриОбмене);
	
КонецПроцедуры

// Структура настроек обмена базовая.
// 
// Возвращаемое значение:
//  Структура:
//   * ДатаНачала - Дата
//   * ДатаОкончания - Дата
//   * НомерСтроки - Число. 
//   * НастройкаВыполненияОбмена - СправочникСсылка.СценарииОбменовДанными - элемент справочника,
//	                             по значениям реквизитов которого будет выполнен обмен данными.
//   * НастройкаВыполненияОбменаНаименование - Строка - наименование настройки выполнения обмена.
//   * УзелИнформационнойБазы - ПланОбменаСсылка - узел плана обмена, для которого выполняется действие обмена данными.
//   * УзелИнформационнойБазыКод - Строка.
//   * УзелИнформационнойБазыНаименование - Строка.
//   * ВидТранспортаОбмена - ПеречислениеСсылка.ВидыТранспортаСообщенийОбмена - вид транспорта,
//	                       который будет использоваться в процессе обмена данными. 
//   * ДействиеПриОбмене - ПеречислениеСсылка.ДействияПриОбмене - выполняемое действие обмена данными.
//   * КоличествоЭлементовВТранзакции - Число.
//   * ПроизводитьЗагрузкуДанных - Булево.
//   * ПроизводитьВыгрузкуДанных - Булево.
//   * ИспользоватьПередачуБольшогоОбъемаДанных - Булево.
//   * Отказ - Булево.
//   * ЭтоОбменВРИБ - Булево.
//   * ОбработкаОбменаДанными - ОбработкаОбъект.КонвертацияОбъектовXDTO.
//                            - ОбработкаОбъект.КонвертацияОбъектовИнформационныхБаз.
//                            - ОбработкаОбъект.КонвертацияОбъектовРаспределенныхИнформационныхБаз.
//   * ОбработкаТранспортаСообщенийОбмена - ОбработкаМенеджер.
//   * ИмяПланаОбмена - Строка.
//   * ТекущийУзелПланаОбмена - ПланОбменаСсылка.
//   * ТекущийУзелПланаОбменаКод - ПланОбменаСсылка.
//   * ОбменПоПравиламКонвертацииОбъектов - Булево.
//   * НаличиеПравилКонвертацииОбязательно - Булево.
//   * ИмяОбработкиТранспортаСообщенийОбмена - Строка. 
//   * КлючСообщенияЖурналаРегистрации - Строка.
//   * НастройкиТранспорта - Произвольный - сохраненные настройки транспорта сообщений обмена внешней системы. 
//   * ПравилаКонвертацииОбъектов - ХранилищеЗначения - зачитанные правила конвертации объектов.
//                              - Неопределено - если правила конвертации не были загружены в базу для 
//   * ПравилаЗагружены - Булево.
//   * ОтладкаОбработчиковВыгрузки - Булево.
//   * ОтладкаОбработчиковЗагрузки - Булево.
//   * ИмяФайлаВнешнейОбработкиОтладкиВыгрузки - Строка.
//   * ИмяФайлаВнешнейОбработкиОтладкиЗагрузки - Строка.
//   * РежимПротоколированияОбменаДанными - Булево.
//   * ИмяФайлаПротоколаОбмена - Строка.
//   * ПродолжитьПриОшибке - Булево.
//   * ДополнительныеПараметры - Структура.
//   * РезультатВыполненияОбмена - ПеречислениеСсылка.РезультатыВыполненияОбмена.
//   * ДействиеПриОбмене - ПеречислениеСсылка.ДействияПриОбмене - выполняемое действие обмена данными.
//   * КоличествоОбъектовОбработано - Число.
//   * СообщениеПриОбмене - Строка.
//   * СтрокаСообщенияОбОшибке - Строка.
//
Функция СтруктураНастроекОбменаБазовая()
	
	СтруктураНастроекОбмена = Новый Структура;
	
	// Структура настроек по полям запроса.
	
	СтруктураНастроекОбмена.Вставить("ДатаНачала", ТекущаяДатаСеанса());
	СтруктураНастроекОбмена.Вставить("ДатаОкончания");
	
	СтруктураНастроекОбмена.Вставить("НомерСтроки");
	СтруктураНастроекОбмена.Вставить("НастройкаВыполненияОбмена");
	СтруктураНастроекОбмена.Вставить("НастройкаВыполненияОбменаНаименование");
	СтруктураНастроекОбмена.Вставить("УзелИнформационнойБазы");
	СтруктураНастроекОбмена.Вставить("УзелИнформационнойБазыКод", "");
	СтруктураНастроекОбмена.Вставить("УзелИнформационнойБазыНаименование", "");
	СтруктураНастроекОбмена.Вставить("ВидТранспортаОбмена");
	СтруктураНастроекОбмена.Вставить("ДействиеПриОбмене");
	СтруктураНастроекОбмена.Вставить("КоличествоЭлементовВТранзакции", 1); // На каждый элемент отдельная транзакция.
	СтруктураНастроекОбмена.Вставить("ПроизводитьЗагрузкуДанных", Ложь);
	СтруктураНастроекОбмена.Вставить("ПроизводитьВыгрузкуДанных", Ложь);
	СтруктураНастроекОбмена.Вставить("ИспользоватьПередачуБольшогоОбъемаДанных", Истина);
	
	// Структура настроек дополнительная.
	СтруктураНастроекОбмена.Вставить("Отказ", Ложь);
	СтруктураНастроекОбмена.Вставить("ЭтоОбменВРИБ", Ложь);
	
	СтруктураНастроекОбмена.Вставить("ОбработкаОбменаДанными");
	СтруктураНастроекОбмена.Вставить("ОбработкаТранспортаСообщенийОбмена");
	
	СтруктураНастроекОбмена.Вставить("ИмяПланаОбмена");
	СтруктураНастроекОбмена.Вставить("ИмяПланаОбменаКорреспондента");
	СтруктураНастроекОбмена.Вставить("ТекущийУзелПланаОбмена");
	СтруктураНастроекОбмена.Вставить("ТекущийУзелПланаОбменаКод");
	
	СтруктураНастроекОбмена.Вставить("ОбменПоПравиламКонвертацииОбъектов",  Ложь);
	СтруктураНастроекОбмена.Вставить("НаличиеПравилКонвертацииОбязательно", Истина);
	
	СтруктураНастроекОбмена.Вставить("ИмяОбработкиТранспортаСообщенийОбмена");
	
	СтруктураНастроекОбмена.Вставить("КлючСообщенияЖурналаРегистрации");
	
	СтруктураНастроекОбмена.Вставить("НастройкиТранспорта");
	
	СтруктураНастроекОбмена.Вставить("ПравилаКонвертацииОбъектов");
	СтруктураНастроекОбмена.Вставить("ПравилаЗагружены", Ложь);
	
	СтруктураНастроекОбмена.Вставить("ОтладкаОбработчиковВыгрузки ", Ложь);
	СтруктураНастроекОбмена.Вставить("ОтладкаОбработчиковЗагрузки", Ложь);
	СтруктураНастроекОбмена.Вставить("ИмяФайлаВнешнейОбработкиОтладкиВыгрузки", "");
	СтруктураНастроекОбмена.Вставить("ИмяФайлаВнешнейОбработкиОтладкиЗагрузки", "");
	СтруктураНастроекОбмена.Вставить("РежимПротоколированияОбменаДанными", Ложь);
	СтруктураНастроекОбмена.Вставить("ИмяФайлаПротоколаОбмена", "");
	СтруктураНастроекОбмена.Вставить("ПродолжитьПриОшибке", Ложь);
	
	// Структура для передачи произвольных дополнительных параметров.
	СтруктураНастроекОбмена.Вставить("ДополнительныеПараметры", Новый Структура);
	
	// Структура для регистрации событий в ЖР.
	СтруктураНастроекОбмена.Вставить("РезультатВыполненияОбмена");
	СтруктураНастроекОбмена.Вставить("ДействиеПриОбмене");
	СтруктураНастроекОбмена.Вставить("КоличествоОбъектовОбработано", 0);
	СтруктураНастроекОбмена.Вставить("СообщениеПриОбмене",           "");
	СтруктураНастроекОбмена.Вставить("СтрокаСообщенияОбОшибке",      "");
	
	Возврат СтруктураНастроекОбмена;
КонецФункции

Процедура ВыполнитьПроверкуОсновныхПолейСтруктурыНастроекОбмена(СтруктураНастроекОбмена)
	
	Если НЕ ЗначениеЗаполнено(СтруктураНастроекОбмена.УзелИнформационнойБазы) Тогда
		
		// Узел информационной базы не должен быть пустым.
		СтрокаСообщенияОбОшибке = НСтр(
		"ru = 'Не задан узел информационной базы, с которой нужно производить обмен информацией. Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
	ИначеЕсли НЕ ЗначениеЗаполнено(СтруктураНастроекОбмена.ВидТранспортаОбмена) Тогда
		
		СтрокаСообщенияОбОшибке = НСтр("ru = 'Не задан вид транспорта обмена. Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
	ИначеЕсли НЕ ЗначениеЗаполнено(СтруктураНастроекОбмена.ДействиеПриОбмене) Тогда
		
		СтрокаСообщенияОбОшибке = НСтр("ru = 'Не указано выполняемое действие (выгрузка / загрузка). Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьПроверкуСтруктурыОбменаНаВалидность(СтруктураНастроекОбмена, ИспользоватьНастройкиТранспорта = Истина)
	
	Если НЕ ЗначениеЗаполнено(СтруктураНастроекОбмена.УзелИнформационнойБазы) Тогда
		
		// Узел информационной базы не должен быть пустым.
		СтрокаСообщенияОбОшибке = НСтр(
		"ru = 'Не задан узел информационной базы, с которой нужно производить обмен информацией. Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
	ИначеЕсли ИспользоватьНастройкиТранспорта И НЕ ЗначениеЗаполнено(СтруктураНастроекОбмена.ВидТранспортаОбмена) Тогда
		
		СтрокаСообщенияОбОшибке = НСтр("ru = 'Не задан вид транспорта обмена. Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
	ИначеЕсли НЕ ЗначениеЗаполнено(СтруктураНастроекОбмена.ДействиеПриОбмене) Тогда
		
		СтрокаСообщенияОбОшибке = НСтр("ru = 'Не указано выполняемое действие (выгрузка / загрузка). Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
	ИначеЕсли СтруктураНастроекОбмена.УзелИнформационнойБазы.ПометкаУдаления Тогда
		
		// Узел информационной базы не должен быть помечен на удаление.
		СтрокаСообщенияОбОшибке = НСтр("ru = 'Узел информационной базы помечен на удаление. Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
	
	ИначеЕсли СтруктураНастроекОбмена.УзелИнформационнойБазы = СтруктураНастроекОбмена.ТекущийУзелПланаОбмена Тогда
		
		// Сами с собой не обмениваемся.
		СтрокаСообщенияОбОшибке = НСтр(
		"ru = 'Нельзя организовать обмен данными с текущим узлом информационной базы. Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
	
	ИначеЕсли ПустаяСтрока(СтруктураНастроекОбмена.УзелИнформационнойБазыКод)
		  ИЛИ ПустаяСтрока(СтруктураНастроекОбмена.ТекущийУзелПланаОбменаКод) Тогда
		
		// У узлов участвующих в обмене должен быть не пустой код.
		СтрокаСообщенияОбОшибке = НСтр("ru = 'Один из узлов обмена имеет пустой код. Обмен отменен.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
	ИначеЕсли СтруктураНастроекОбмена.ОтладкаОбработчиковВыгрузки Тогда
		
		ФайлОбработкиВыгрузки = Новый Файл(СтруктураНастроекОбмена.ИмяФайлаВнешнейОбработкиОтладкиВыгрузки);
		
		Если Не ФайлОбработкиВыгрузки.Существует() Тогда
			
			СтрокаСообщенияОбОшибке = НСтр("ru = 'Файл внешней обработки для отладки выгрузки не существует. Обмен отменен.'",
				ОбщегоНазначения.КодОсновногоЯзыка());
			ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
			
			ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
			
		КонецЕсли;
		
	ИначеЕсли СтруктураНастроекОбмена.ОтладкаОбработчиковЗагрузки Тогда
		
		ФайлОбработкиЗагрузки = Новый Файл(СтруктураНастроекОбмена.ИмяФайлаВнешнейОбработкиОтладкиЗагрузки);
		
		Если Не ФайлОбработкиЗагрузки.Существует() Тогда
			
			СтрокаСообщенияОбОшибке = НСтр("ru = 'Файл внешней обработки для отладки загрузки не существует. Обмен отменен.'",
				ОбщегоНазначения.КодОсновногоЯзыка());
			ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
			
			ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьИнициализациюОбработкиОбмена(СтруктураНастроекОбмена)
	
	// Если настройки содержат ошибки, то не производим инициализацию.
	Если СтруктураНастроекОбмена.Отказ Тогда
		Возврат;
	КонецЕсли;
	
	// создание
	ОбработкаОбменаДанными = Обработки.КонвертацияОбъектовРаспределенныхИнформационныхБаз.Создать();
	
	// инициализация свойств
	ОбработкаОбменаДанными.УзелИнформационнойБазы          = СтруктураНастроекОбмена.УзелИнформационнойБазы;
	ОбработкаОбменаДанными.КоличествоЭлементовВТранзакции  = СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции;
	ОбработкаОбменаДанными.КлючСообщенияЖурналаРегистрации = СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации;
	
	СтруктураНастроекОбмена.Вставить("ОбработкаОбменаДанными", ОбработкаОбменаДанными);
	
КонецПроцедуры

Процедура ВыполнитьИнициализациюОбработкиОбменаПоПравиламКонвертации(СтруктураНастроекОбмена)
	
	Перем ОбработкаОбменаДанными;
	
	// Если настройки содержат ошибки, то не производим инициализацию.
	Если СтруктураНастроекОбмена.Отказ Тогда
		Возврат;
	КонецЕсли;
	
	Если СтруктураНастроекОбмена.ПроизводитьВыгрузкуДанных Тогда
		
		ОбработкаОбменаДанными = ОбработкаОбменаДаннымиДляВыгрузки(СтруктураНастроекОбмена);
		
	ИначеЕсли СтруктураНастроекОбмена.ПроизводитьЗагрузкуДанных Тогда
		
		ОбработкаОбменаДанными = ОбработкаОбменаДаннымиДляЗагрузки(СтруктураНастроекОбмена);
		
	КонецЕсли;
	
	СтруктураНастроекОбмена.Вставить("ОбработкаОбменаДанными", ОбработкаОбменаДанными);
	
КонецПроцедуры

Процедура ВыполнитьИнициализациюОбработкиТранспортаСообщенийОбмена(СтруктураНастроекОбмена)
	
	Если СтруктураНастроекОбмена.ВидТранспортаОбмена = Перечисления.ВидыТранспортаСообщенийОбмена.ВнешняяСистема Тогда
		ВыполнитьИнициализациюОбработкиТранспортаСообщенийОбменаСВнешнейСистемой(СтруктураНастроекОбмена);
		Возврат;
	КонецЕсли;
	
	// Создаем обработку транспорта.
	ОбработкаТранспортаСообщенийОбмена = Обработки[СтруктураНастроекОбмена.ИмяОбработкиТранспортаСообщенийОбмена].Создать();
	
	ЭтоИсходящееСообщение = СтруктураНастроекОбмена.ПроизводитьВыгрузкуДанных;
	
	Транслитерация = Неопределено;
	СловарьНастроек = Новый Соответствие;
	СловарьНастроек.Вставить(Перечисления.ВидыТранспортаСообщенийОбмена.FILE,  "FILEТранслитерироватьИменаФайловСообщенийОбмена");
	СловарьНастроек.Вставить(Перечисления.ВидыТранспортаСообщенийОбмена.EMAIL, "EMAILТранслитерироватьИменаФайловСообщенийОбмена");
	СловарьНастроек.Вставить(Перечисления.ВидыТранспортаСообщенийОбмена.FTP,   "FTPТранслитерироватьИменаФайловСообщенийОбмена");
	
	ИмяСвойстваТранслитерация = СловарьНастроек.Получить(СтруктураНастроекОбмена.ВидТранспортаОбмена);
	Если ЗначениеЗаполнено(ИмяСвойстваТранслитерация) Тогда
		СтруктураНастроекОбмена.НастройкиТранспорта.Свойство(ИмяСвойстваТранслитерация, Транслитерация);
	КонецЕсли;
	
	Транслитерация = ?(Транслитерация = Неопределено, Ложь, Транслитерация);
	
	// Заполняем общие реквизиты, одинаковые для всех обработок транспорта.
	ОбработкаТранспортаСообщенийОбмена.ШаблонИмениФайлаСообщения = ШаблонИмениФайлаСообщения(
		СтруктураНастроекОбмена.ТекущийУзелПланаОбмена,
		СтруктураНастроекОбмена.УзелИнформационнойБазы,
		ЭтоИсходящееСообщение,
		Транслитерация);
	
	// Заполняем настойки транспорта, различные для каждой обработки транспорта.
	ЗаполнитьЗначенияСвойств(ОбработкаТранспортаСообщенийОбмена, СтруктураНастроекОбмена.НастройкиТранспорта);
	
	// Инициализируем транспорт
	ОбработкаТранспортаСообщенийОбмена.Инициализация();
	
	СтруктураНастроекОбмена.Вставить("ОбработкаТранспортаСообщенийОбмена", ОбработкаТранспортаСообщенийОбмена);
	
КонецПроцедуры

Функция ОбработкаОбменаДаннымиДляВыгрузки(СтруктураНастроекОбмена)
	
	МенеджерОбработки = ?(ЭтоПланОбменаXDTO(СтруктураНастроекОбмена.УзелИнформационнойБазы),
		Обработки.КонвертацияОбъектовXDTO,
		Обработки.КонвертацияОбъектовИнформационныхБаз);
	
	ОбработкаОбменаДанными = МенеджерОбработки.Создать();
	
	ОбработкаОбменаДанными.РежимОбмена = "Выгрузка";
	
	// Если обработка поддерживает механизм правил конвертации.
	Если ОбработкаОбменаДанными.Метаданные().Реквизиты.Найти("ИмяФайлаПравилОбмена") <> Неопределено Тогда
		УстановитьПравилаОбменаВыгрузкиДанных(ОбработкаОбменаДанными, СтруктураНастроекОбмена);
		ОбработкаОбменаДанными.НеВыгружатьОбъектыПоСсылкам = Истина;
		ОбработкаОбменаДанными.ИмяФайлаПравилОбмена        = "1";
	КонецЕсли;
	
	// Если обработка поддерживает механизм фонового обмена.
	Если ОбработкаОбменаДанными.Метаданные().Реквизиты.Найти("УзелДляФоновогоОбмена") <> Неопределено Тогда
		ОбработкаОбменаДанными.УзелДляФоновогоОбмена = Неопределено;
	КонецЕсли;
		
	ОбработкаОбменаДанными.УзелДляОбмена = СтруктураНастроекОбмена.УзелИнформационнойБазы;
	
	УстановитьОбщиеПараметрыДляОбработкиОбменаДанными(ОбработкаОбменаДанными, СтруктураНастроекОбмена);
	
	Возврат ОбработкаОбменаДанными;
	
КонецФункции

Функция ОбработкаОбменаДаннымиДляЗагрузки(СтруктураНастроекОбмена)
	
	МенеджерОбработки = ?(ЭтоПланОбменаXDTO(СтруктураНастроекОбмена.УзелИнформационнойБазы),
		Обработки.КонвертацияОбъектовXDTO,
		Обработки.КонвертацияОбъектовИнформационныхБаз);
	
	ОбработкаОбменаДанными = МенеджерОбработки.Создать();
	
	ОбработкаОбменаДанными.РежимОбмена = "Загрузка";
	ОбработкаОбменаДанными.УзелОбменаЗагрузкаДанных = СтруктураНастроекОбмена.УзелИнформационнойБазы;
	
	Если ОбработкаОбменаДанными.Метаданные().Реквизиты.Найти("ИмяФайлаПравилОбмена") <> Неопределено Тогда
		УстановитьПравилаОбменаЗагрузкиДанных(ОбработкаОбменаДанными, СтруктураНастроекОбмена);
	КонецЕсли;
	
	УстановитьОбщиеПараметрыДляОбработкиОбменаДанными(ОбработкаОбменаДанными, СтруктураНастроекОбмена);
	
	Возврат ОбработкаОбменаДанными
	
КонецФункции

Процедура УстановитьОбщиеПараметрыДляОбработкиОбменаДанными(ОбработкаОбменаДанными, СтруктураНастроекОбмена, ОбменСБСП20 = Ложь)
	
	ОбработкаОбменаДанными.ДописыватьДанныеВПротоколОбмена = Ложь;
	ОбработкаОбменаДанными.ВыгружатьТолькоРазрешенные      = Ложь;
	
	ОбработкаОбменаДанными.ИспользоватьТранзакции         = СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции <> 1;
	ОбработкаОбменаДанными.КоличествоОбъектовНаТранзакцию = СтруктураНастроекОбмена.КоличествоЭлементовВТранзакции;
	
	ОбработкаОбменаДанными.КлючСообщенияЖурналаРегистрации = СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации;
	
	Если Не ОбменСБСП20 Тогда
		
		УстановитьНастройкиРежимаОтладкиДляОбработки(ОбработкаОбменаДанными, СтруктураНастроекОбмена);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура УстановитьПравилаОбменаВыгрузкиДанных(ОбработкаОбменаДаннымиXML, СтруктураНастроекОбмена)
	
	ПравилаКонвертацииОбъектов = РегистрыСведений.ПравилаДляОбменаДанными.ЗачитанныеПравилаКонвертацииОбъектов(СтруктураНастроекОбмена.ИмяПланаОбмена);
	
	Если ПравилаКонвертацииОбъектов = Неопределено Тогда
		
		// Правила обмена должны быть указаны.
		СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не заданы правила конвертации для плана обмена %1. Выгрузка данных отменена.'", ОбщегоНазначения.КодОсновногоЯзыка()),
			СтруктураНастроекОбмена.ИмяПланаОбмена);
		ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
		Возврат;
	КонецЕсли;
	
	ОбработкаОбменаДаннымиXML.СохраненныеНастройки = ПравилаКонвертацииОбъектов;
	
	Попытка
		ОбработкаОбменаДаннымиXML.ВосстановитьПравилаИзВнутреннегоФормата();
	Исключение
		ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()), СтруктураНастроекОбмена, Истина);
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		Возврат;
	КонецПопытки;
	
КонецПроцедуры

Процедура УстановитьПравилаОбменаЗагрузкиДанных(ОбработкаОбменаДаннымиXML, СтруктураНастроекОбмена)
	
	ПравилаКонвертацииОбъектов = РегистрыСведений.ПравилаДляОбменаДанными.ЗачитанныеПравилаКонвертацииОбъектов(СтруктураНастроекОбмена.ИмяПланаОбмена, Истина);
	
	Если ПравилаКонвертацииОбъектов = Неопределено Тогда
	
		Если Не СтруктураНастроекОбмена.Свойство("НаличиеПравилКонвертацииОбязательно")
			Или СтруктураНастроекОбмена.НаличиеПравилКонвертацииОбязательно = Истина Тогда
		
			// Правила обмена должны быть указаны.
			НСтрока = НСтр("ru = 'Не заданы правила конвертации для плана обмена %1. Загрузка данных отменена.'",
				ОбщегоНазначения.КодОсновногоЯзыка());
			СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтрока, СтруктураНастроекОбмена.ИмяПланаОбмена);
			ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
			ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		
			Возврат;
			
		КонецЕсли;
			
	КонецЕсли;
	
	ОбработкаОбменаДаннымиXML.СохраненныеНастройки = ПравилаКонвертацииОбъектов;
	
	Попытка
		ОбработкаОбменаДаннымиXML.ВосстановитьПравилаИзВнутреннегоФормата();
	Исключение
		ЗаписьЖурналаРегистрацииОбменаДанными(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()), СтруктураНастроекОбмена, Истина);
		ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена);
		Возврат;
	КонецПопытки;
	
КонецПроцедуры

// Считывает настройки отладки из ИБ и устанавливает их для структуры обмена.
//
Процедура УстановитьНастройкиРежимаОтладкиДляСтруктуры(СтруктураНастроекОбмена, ЭтоВнешнееСоединение = Ложь)
	
	ТекстЗапроса = "ВЫБРАТЬ
	|	ВЫБОР
	|		КОГДА &ПроизводитьВыгрузку
	|			ТОГДА ПравилаДляОбменаДанными.РежимОтладкиВыгрузки
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК ОтладкаОбработчиковВыгрузки,
	|	ВЫБОР
	|		КОГДА &ПроизводитьВыгрузку
	|			ТОГДА ПравилаДляОбменаДанными.ИмяФайлаОбработкиДляОтладкиВыгрузки
	|		ИНАЧЕ """"
	|	КОНЕЦ КАК ИмяФайлаВнешнейОбработкиОтладкиВыгрузки,
	|	ВЫБОР
	|		КОГДА &ПроизводитьЗагрузку
	|			ТОГДА ПравилаДляОбменаДанными.РежимОтладкиЗагрузки
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК ОтладкаОбработчиковЗагрузки,
	|	ВЫБОР
	|		КОГДА &ПроизводитьЗагрузку
	|			ТОГДА ПравилаДляОбменаДанными.ИмяФайлаОбработкиДляОтладкиЗагрузки
	|		ИНАЧЕ """"
	|	КОНЕЦ КАК ИмяФайлаВнешнейОбработкиОтладкиЗагрузки,
	|	ПравилаДляОбменаДанными.РежимПротоколированияОбменаДанными КАК РежимПротоколированияОбменаДанными,
	|	ПравилаДляОбменаДанными.ИмяФайлаПротоколаОбмена КАК ИмяФайлаПротоколаОбмена,
	|	ПравилаДляОбменаДанными.НеОстанавливатьПоОшибке КАК ПродолжитьПриОшибке
	|ИЗ
	|	РегистрСведений.ПравилаДляОбменаДанными КАК ПравилаДляОбменаДанными
	|ГДЕ
	|	ПравилаДляОбменаДанными.ИмяПланаОбмена = &ИмяПланаОбмена
	|	И ПравилаДляОбменаДанными.ВидПравил = ЗНАЧЕНИЕ(Перечисление.ВидыПравилДляОбменаДанными.ПравилаКонвертацииОбъектов)
	|	И ПравилаДляОбменаДанными.РежимОтладки";
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	
	ПроизводитьВыгрузкуДанных = Ложь;
	Если Не СтруктураНастроекОбмена.Свойство("ПроизводитьВыгрузкуДанных", ПроизводитьВыгрузкуДанных) Тогда
		ПроизводитьВыгрузкуДанных = (СтруктураНастроекОбмена.ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ВыгрузкаДанных);
	КонецЕсли;
	
	ПроизводитьЗагрузкуДанных = Ложь;
	Если Не СтруктураНастроекОбмена.Свойство("ПроизводитьЗагрузкуДанных", ПроизводитьЗагрузкуДанных) Тогда
		ПроизводитьЗагрузкуДанных = (СтруктураНастроекОбмена.ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ЗагрузкаДанных);
	КонецЕсли;
	
	Запрос.УстановитьПараметр("ИмяПланаОбмена", СтруктураНастроекОбмена.ИмяПланаОбмена);
	Запрос.УстановитьПараметр("ПроизводитьВыгрузку", ПроизводитьВыгрузкуДанных);
	Запрос.УстановитьПараметр("ПроизводитьЗагрузку", ПроизводитьЗагрузкуДанных);
	
	ИмяФайлаПротокола = "";
	Если ЭтоВнешнееСоединение И СтруктураНастроекОбмена.Свойство("ИмяФайлаПротоколаОбмена", ИмяФайлаПротокола)
		И Не ПустаяСтрока(ИмяФайлаПротокола) Тогда
		
		СтруктураНастроекОбмена.ИмяФайлаПротоколаОбмена = ДобавитьЛитералКИмениФайла(ИмяФайлаПротокола, "ВнешнееСоединение")
	
	КонецЕсли;
	
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
	
		Результат = Запрос.Выполнить();
		
		Если Не Результат.Пустой() Тогда
		
			ТаблицаНастроек = Результат.Выгрузить();
			СтрокаТаблицы = ТаблицаНастроек[0];
			
			ЗаполнитьЗначенияСвойств(СтруктураНастроекОбмена, СтрокаТаблицы);
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Считывает настройки отладки из ИБ и устанавливает их для структуры настроек обмена.
//
Процедура УстановитьНастройкиРежимаОтладкиДляОбработки(ОбработкаОбменаДанными, СтруктураНастроекОбмена)
	
	Если СтруктураНастроекОбмена.Свойство("ИмяФайлаВнешнейОбработкиОтладкиВыгрузки")
		И ОбработкаОбменаДанными.Метаданные().Реквизиты.Найти("ИмяФайлаВнешнейОбработкиОтладкиВыгрузки") <> Неопределено Тогда
		
		ОбработкаОбменаДанными.ОтладкаОбработчиковВыгрузки = СтруктураНастроекОбмена.ОтладкаОбработчиковВыгрузки;
		ОбработкаОбменаДанными.ОтладкаОбработчиковЗагрузки = СтруктураНастроекОбмена.ОтладкаОбработчиковЗагрузки;
		ОбработкаОбменаДанными.ИмяФайлаВнешнейОбработкиОтладкиВыгрузки = СтруктураНастроекОбмена.ИмяФайлаВнешнейОбработкиОтладкиВыгрузки;
		ОбработкаОбменаДанными.ИмяФайлаВнешнейОбработкиОтладкиЗагрузки = СтруктураНастроекОбмена.ИмяФайлаВнешнейОбработкиОтладкиЗагрузки;
		ОбработкаОбменаДанными.РежимПротоколированияОбменаДанными = СтруктураНастроекОбмена.РежимПротоколированияОбменаДанными;
		ОбработкаОбменаДанными.ИмяФайлаПротоколаОбмена = СтруктураНастроекОбмена.ИмяФайлаПротоколаОбмена;
		ОбработкаОбменаДанными.ПродолжитьПриОшибке = СтруктураНастроекОбмена.ПродолжитьПриОшибке;
		
		Если СтруктураНастроекОбмена.РежимПротоколированияОбменаДанными Тогда
			
			Если СтруктураНастроекОбмена.ИмяФайлаПротоколаОбмена = "" Тогда
				ОбработкаОбменаДанными.ВыводВОкноСообщенийИнформационныхСообщений = Истина;
				ОбработкаОбменаДанными.ВыводВПротоколИнформационныхСообщений = Ложь;
			Иначе
				ОбработкаОбменаДанными.ВыводВОкноСообщенийИнформационныхСообщений = Ложь;
				ОбработкаОбменаДанными.ВыводВПротоколИнформационныхСообщений = Истина;
				ОбработкаОбменаДанными.ИмяФайлаПротоколаОбмена = СтруктураНастроекОбмена.ИмяФайлаПротоколаОбмена;
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Устанавливает для обработки настройки выгрузки.
//
Процедура УстановитьНастройкиОтладкиВыгрузкиДляПравилОбмена(ОбработкаОбменаДанными, ИмяПланаОбмена, РежимОтладки) Экспорт
	
	ТекстЗапроса = "ВЫБРАТЬ
	|	ПравилаДляОбменаДанными.РежимОтладкиВыгрузки КАК ОтладкаОбработчиковВыгрузки,
	|	ПравилаДляОбменаДанными.ИмяФайлаОбработкиДляОтладкиВыгрузки КАК ИмяФайлаВнешнейОбработкиОтладкиВыгрузки
	|ИЗ
	|	РегистрСведений.ПравилаДляОбменаДанными КАК ПравилаДляОбменаДанными
	|ГДЕ
	|	ПравилаДляОбменаДанными.ИмяПланаОбмена = &ИмяПланаОбмена
	|	И ПравилаДляОбменаДанными.ВидПравил = ЗНАЧЕНИЕ(Перечисление.ВидыПравилДляОбменаДанными.ПравилаКонвертацииОбъектов)
	|	И &РежимОтладки = ИСТИНА";
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("ИмяПланаОбмена", ИмяПланаОбмена);
	Запрос.УстановитьПараметр("РежимОтладки", РежимОтладки);
	
	Результат = Запрос.Выполнить();
	
	Если Результат.Пустой() Или ОбщегоНазначения.РазделениеВключено() Тогда
		
		ОбработкаОбменаДанными.ОтладкаОбработчиковВыгрузки = Ложь;
		ОбработкаОбменаДанными.ИмяФайлаВнешнейОбработкиОтладкиВыгрузки = "";
		
	Иначе
		
		ТаблицаНастроек = Результат.Выгрузить();
		НастройкиОтладки = ТаблицаНастроек[0];
		
		ЗаполнитьЗначенияСвойств(ОбработкаОбменаДанными, НастройкиОтладки);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗафиксироватьЗавершениеИнициализацииОбмена(СтруктураНастроекОбмена)
	
	СтруктураНастроекОбмена.Отказ = Истина;
	СтруктураНастроекОбмена.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Отменено;
	
КонецПроцедуры

Функция ШаблонИмениФайлаСообщения(ТекущийУзелПланаОбмена, УзелИнформационнойБазы, ЭтоИсходящееСообщение, Транслитерация = Ложь, ИспользоватьВиртуальныйКодУзлаПриПолучении = Ложь) Экспорт
	
	Если ЭтоИсходящееСообщение Тогда
		КодОтправителя = ИдентификаторЭтогоУзлаДляОбмена(УзелИнформационнойБазы);
		КодПолучателя  = ИдентификаторУзлаКорреспондентаДляОбмена(УзелИнформационнойБазы);
	Иначе
		КодОтправителя = ИдентификаторУзлаКорреспондентаДляОбмена(УзелИнформационнойБазы);
		КодПолучателя  = ИдентификаторЭтогоУзлаДляОбмена(УзелИнформационнойБазы);
	КонецЕсли;
	
	Если ЭтоИсходящееСообщение Или ИспользоватьВиртуальныйКодУзлаПриПолучении Тогда
		// Обмен с корреспондентом, который не знаком с новым кодом предопределенного узла -
		// при формировании имени файла сообщения обмена вместо кода предопределенного узла используется код из регистра.
		ПсевдонимПредопределенногоУзла = ПсевдонимПредопределенногоУзла(УзелИнформационнойБазы);
		Если ЗначениеЗаполнено(ПсевдонимПредопределенногоУзла) Тогда
			Если ЭтоИсходящееСообщение Тогда
				КодОтправителя = ПсевдонимПредопределенногоУзла;
			Иначе
				КодПолучателя = ПсевдонимПредопределенногоУзла;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	ИмяФайлаСообщения = ИмяФайлаСообщенияОбмена(КодОтправителя, КодПолучателя, ЭтоИсходящееСообщение);
	
	// Учитываем настройку транслитерации для узла плана обмена.
	Если Транслитерация Тогда
		ИмяФайлаСообщения = СтроковыеФункции.СтрокаЛатиницей(ИмяФайлаСообщения);
	КонецЕсли;
	
	Возврат ИмяФайлаСообщения;
	
КонецФункции

Процедура ВыполнитьИнициализациюОбработкиТранспортаСообщенийОбменаСВнешнейСистемой(СтруктураНастроекОбмена)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ОбменДаннымиСВнешнимиСистемами") Тогда
		
		ОбработкаТранспортаСообщенийОбмена = Обработки[СтруктураНастроекОбмена.ИмяОбработкиТранспортаСообщенийОбмена].Создать();
		
		ПараметрыПодключения = РегистрыСведений.НастройкиТранспортаОбменаДанными.НастройкиТранспортаВнешнейСистемы(
			СтруктураНастроекОбмена.УзелИнформационнойБазы);
		
		// Инициализируем транспорт.
		ОбработкаТранспортаСообщенийОбмена.Инициализация(ПараметрыПодключения);
		
		СтруктураНастроекОбмена.Вставить("ОбработкаТранспортаСообщенийОбмена", ОбработкаТранспортаСообщенийОбмена);
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОбщегоНазначения_СлужебныеПроцедурыИФункции

Процедура ПолучитьОбщиеНастройкиУзловИнформационныхБаз(МенеджерВременныхТаблиц)
	
	Запрос = Новый Запрос;
	
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		ТекстЗапросаРезультат =
		"ВЫБРАТЬ
		|	ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.ВерсияКорреспондента, """") КАК ВерсияКорреспондента,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.ПрефиксКорреспондента, """") КАК ПрефиксКорреспондента,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.НастройкаЗавершена, ЛОЖЬ) КАК НастройкаЗавершена,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.ПереходНаWS_Этап, 0) КАК ПереходНаWS_Этап,
		|	ЕСТЬNULL(НастройкиТранспортаОбменаДанными.ВидТранспортаСообщенийОбменаПоУмолчанию, """") КАК ВидТранспорта,
		|	ЕСТЬNULL(ОбщиеНастройкиУзловИнформационныхБаз.СинхронизацияНедоступна, ЛОЖЬ) КАК СинхронизацияНедоступна
		|ПОМЕСТИТЬ ОбщиеНастройкиУзловИнформационныхБаз
		|ИЗ
		|	РегистрСведений.ОбщиеНастройкиУзловИнформационныхБаз КАК ОбщиеНастройкиУзловИнформационныхБаз
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиТранспортаОбменаДанными КАК НастройкиТранспортаОбменаДанными
		|		ПО ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы = НастройкиТранспортаОбменаДанными.Корреспондент";
		
	Иначе
		
		ТекстЗапросаРезультат =
		"ВЫБРАТЬ
		|	NULL КАК УзелИнформационнойБазы,
		|	"""" КАК ВерсияКорреспондента,
		|	"""" КАК ПрефиксКорреспондента,
		|	ЛОЖЬ КАК НастройкаЗавершена,
		|	0 КАК ПереходНаWS_Этап,
		|	"""" КАК ВидТранспорта,
		|	ЛОЖЬ КАК СинхронизацияНедоступна
		|ПОМЕСТИТЬ ОбщиеНастройкиУзловИнформационныхБаз";
		
	КонецЕсли;
	
	Запрос.Текст = ТекстЗапросаРезультат;
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	Запрос.Выполнить();
	
КонецПроцедуры

Функция СправочникиПланаОбмена(Знач ИмяПланаОбмена)
	
	Если ТипЗнч(ИмяПланаОбмена) <> Тип("Строка") Тогда
		
		ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(ИмяПланаОбмена);
		
	КонецЕсли;
	
	Результат = Новый Массив;
	
	СоставПланаОбмена = Метаданные.ПланыОбмена[ИмяПланаОбмена].Состав;
	
	Для Каждого Элемент Из СоставПланаОбмена Цикл
		
		Если ОбщегоНазначения.ЭтоСправочник(Элемент.Метаданные)
			ИЛИ ОбщегоНазначения.ЭтоПланВидовХарактеристик(Элемент.Метаданные) Тогда
			
			Результат.Добавить(Элемент.Метаданные);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// См. ТекущиеДелаПереопределяемый.ПриОпределенииОбработчиковТекущихДел
Процедура ПриЗаполненииСпискаТекущихДелПредупрежденияСинхронизации(ТекущиеДела)
	
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	Если Не ПравоДоступа("Просмотр", Метаданные.РегистрыСведений.РезультатыОбменаДанными)
		Или МодульТекущиеДелаСервер.ДелоОтключено("ПредупрежденияПриСинхронизации") Тогда
		Возврат;
	КонецЕсли;
	
	ПланыОбменаБСП = ОбменДаннымиПовтИсп.ПланыОбменаБСП();
	Если ПланыОбменаБСП.Количество() > 0 Тогда
		
		ТаблицаМонитора = ТаблицаМонитораОбменаДанными(ПланыОбменаБСП);
		СтруктураРезультат = РегистрыСведений.РезультатыОбменаДанными.КоличествоПредупрежденийДляЭлементаФормы(ТаблицаМонитора.ВыгрузитьКолонку("УзелИнформационнойБазы"));
		
	Иначе
		
		СтруктураРезультат = Новый Структура("Количество, Заголовок", 0, "");
		
	КонецЕсли;
	
	// Процедура вызывается только при наличии подсистемы "Текущие дела", поэтому здесь
	// не делается проверка существования подсистемы.
	Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта(Метаданные.ОбщиеФормы.НастройкиСинхронизацииДанных.ПолноеИмя());
	
	Для Каждого Раздел Из Разделы Цикл
		
		ИдентификаторПредупрежденияПриСинхронизации = "ПредупрежденияПриСинхронизации" + СтрЗаменить(Раздел.ПолноеИмя(), ".", "");
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор  = ИдентификаторПредупрежденияПриСинхронизации;
		Дело.ЕстьДела       = СтруктураРезультат.Количество > 0;
		Дело.Количество     = СтруктураРезультат.Количество;
		Дело.Представление  = НСтр("ru = 'Предупреждения'");
		Дело.Форма          = "РегистрСведений.РезультатыОбменаДанными.Форма.ПредупрежденияСинхронизаций";
		Дело.Владелец       = Раздел;
		
	КонецЦикла;
	
КонецПроцедуры

// См. ТекущиеДелаПереопределяемый.ПриОпределенииОбработчиковТекущихДел
Процедура ПриЗаполненииСпискаТекущихДелПроверитьЗацикливание(ТекущиеДела)
	
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	Если Не ПравоДоступа("Редактирование", Метаданные.РегистрыСведений.КонтурСинхронизации)
		Или МодульТекущиеДелаСервер.ДелоОтключено("ПредупрежденияПриСинхронизацииЗацикливание") Тогда
		Возврат;
	КонецЕсли;
	
	ПланыОбменаБСП = ОбменДаннымиПовтИсп.ПланыОбменаБСП();
	ЕстьЗацикливание = ПланыОбменаБСП.Количество() > 0 И ОбменДаннымиКонтрольЗацикливания.ЕстьЗацикливание();
		
	// Процедура вызывается только при наличии подсистемы "Текущие дела", поэтому здесь
	// не делается проверка существования подсистемы.
	Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта(Метаданные.ОбщиеФормы.НастройкиСинхронизацииДанных.ПолноеИмя());
	
	Для Каждого Раздел Из Разделы Цикл
		
		ИдентификаторПредупрежденияПриСинхронизации = "ПредупрежденияПриСинхронизацииЗацикливание" + СтрЗаменить(Раздел.ПолноеИмя(), ".", "");
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор  = ИдентификаторПредупрежденияПриСинхронизации;
		Дело.ЕстьДела       = ЕстьЗацикливание;
		Дело.Представление  = НСтр("ru = 'Обнаружено зацикливание синхронизаций'");
		Дело.Форма          = "РегистрСведений.КонтурСинхронизации.Форма.ЗацикливаниеСинхронизации";
		Дело.Владелец       = Раздел;
		Дело.Важное			= Истина;
	
	КонецЦикла;
	
КонецПроцедуры

// См. ТекущиеДелаПереопределяемый.ПриОпределенииОбработчиковТекущихДел.
Процедура ПриЗаполненииСпискаТекущихДелПроверитьСовместимостьСТекущейВерсией(ТекущиеДела)
	
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	Если Не ПравоДоступа("Редактирование", Метаданные.РегистрыСведений.ПравилаДляОбменаДанными)
		Или МодульТекущиеДелаСервер.ДелоОтключено("ПравилаОбмена") Тогда
		Возврат;
	КонецЕсли;
	
	// Если в командном интерфейсе нет раздела к которому относится регистр сведений, дело не добавляется.
	Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта("РегистрСведений.ПравилаДляОбменаДанными");
	Если Разделы.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	ВывестиДело = Истина;
	ПровереноНаВерсию = ХранилищеОбщихНастроек.Загрузить("ТекущиеДела", "ПланыОбмена");
	Если ПровереноНаВерсию <> Неопределено Тогда
		ВерсияМассив  = СтрРазделить(Метаданные.Версия, ".");
		ТекущаяВерсия = ВерсияМассив[0] + ВерсияМассив[1] + ВерсияМассив[2];
		Если ПровереноНаВерсию = ТекущаяВерсия Тогда
			ВывестиДело = Ложь; // Дополнительные отчеты и обработки проверены на текущей версии.
		КонецЕсли;
	КонецЕсли;
	
	ПланыОбменаСПравиламиИзФайла = ПланыОбменаСПравиламиИзФайла();
	
	Для Каждого Раздел Из Разделы Цикл
		ИдентификаторРаздела = "ПроверитьСовместимостьСТекущейВерсией" + СтрЗаменить(Раздел.ПолноеИмя(), ".", "");
		
		// Добавление дела.
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор = "ПравилаОбмена";
		Дело.ЕстьДела      = ВывестиДело И ПланыОбменаСПравиламиИзФайла > 0;
		Дело.Представление = НСтр("ru = 'Правила обмена'");
		Дело.Количество    = ПланыОбменаСПравиламиИзФайла;
		Дело.Форма         = "РегистрСведений.ПравилаДляОбменаДанными.Форма.ПроверкаСинхронизацииДанных";
		Дело.Владелец      = ИдентификаторРаздела;
		
		// Проверка наличия группы дела. Если группа отсутствует - добавляем.
		ГруппаДела = ТекущиеДела.Найти(ИдентификаторРаздела, "Идентификатор");
		Если ГруппаДела = Неопределено Тогда
			ГруппаДела = ТекущиеДела.Добавить();
			ГруппаДела.Идентификатор = ИдентификаторРаздела;
			ГруппаДела.ЕстьДела      = Дело.ЕстьДела;
			ГруппаДела.Представление = НСтр("ru = 'Проверить совместимость'");
			Если Дело.ЕстьДела Тогда
				ГруппаДела.Количество = Дело.Количество;
			КонецЕсли;
			ГруппаДела.Владелец = Раздел;
		Иначе
			Если Не ГруппаДела.ЕстьДела Тогда
				ГруппаДела.ЕстьДела = Дело.ЕстьДела;
			КонецЕсли;
			
			Если Дело.ЕстьДела Тогда
				ГруппаДела.Количество = ГруппаДела.Количество + Дело.Количество;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ДополнительныеСвойстваПланаОбменаСтрокой(Знач СвойстваСтрокой)
	
	Результат = "";
	
	Шаблон = "ПланыОбмена.[СвойствоСтрокой] КАК [СвойствоСтрокой]";
	
	СвойстваМассив = СтрРазделить(СвойстваСтрокой, ",", Ложь);
	
	Для Каждого СвойствоСтрокой Из СвойстваМассив Цикл
		
		СвойствоСтрокойВЗапросе = СтрЗаменить(Шаблон, "[СвойствоСтрокой]", СвойствоСтрокой);
		
		Результат = Результат + СвойствоСтрокойВЗапросе + ", ";
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция ФильтрПлановОбменаПоПризнакуРазделенияДанных(ПланыОбменаМассив)
	
	Результат = Новый Массив;
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		
		Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
			
			Для Каждого ИмяПланаОбмена Из ПланыОбменаМассив Цикл
				
				Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
					МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
					ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных("ПланОбмена." + ИмяПланаОбмена);
				Иначе
					ЭтоРазделенныйОбъектМетаданных = Ложь;
				КонецЕсли;
				
				Если ЭтоРазделенныйОбъектМетаданных Тогда
					
					Результат.Добавить(ИмяПланаОбмена);
					
				КонецЕсли;
				
			КонецЦикла;
			
		Иначе
			
			Для Каждого ИмяПланаОбмена Из ПланыОбменаМассив Цикл
				
				Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
					МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
					ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных("ПланОбмена." + ИмяПланаОбмена);
				Иначе
					ЭтоРазделенныйОбъектМетаданных = Ложь;
				КонецЕсли;
				
				Если Не ЭтоРазделенныйОбъектМетаданных Тогда
					
					Результат.Добавить(ИмяПланаОбмена);
					
				КонецЕсли;
				
			КонецЦикла;
			
		КонецЕсли;
		
	Иначе
		
		Для Каждого ИмяПланаОбмена Из ПланыОбменаМассив Цикл
			
			Результат.Добавить(ИмяПланаОбмена);
			
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция ФильтрПлановОбменаПоПризнакуАвтономнойРаботы(ПланыОбменаМассив)
	
	Результат = Новый Массив;
	
	Для Каждого ИмяПланаОбмена Из ПланыОбменаМассив Цикл
		
		Если ИмяПланаОбмена <> ОбменДаннымиПовтИсп.ПланОбменаАвтономнойРаботы() Тогда
			
			Результат.Добавить(ИмяПланаОбмена);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Процедура удаляет неактуальные записи в регистре сведений.
// Запись считается неактуальной, если план обмена, для которого была создана запись,
// был переименован или удален.
//
// Параметры:
//  Нет.
// 
Процедура УдалитьНеактуальныеЗаписиВРегистреПравилДляОбменаДанными()
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ПравилаДляОбменаДанными.ИмяПланаОбмена КАК ИмяПланаОбмена
	|ИЗ
	|	РегистрСведений.ПравилаДляОбменаДанными КАК ПравилаДляОбменаДанными
	|ГДЕ
	|	НЕ ПравилаДляОбменаДанными.ИмяПланаОбмена В (&ПланыОбменаБСП)");
	Запрос.УстановитьПараметр("ПланыОбменаБСП", ОбменДаннымиПовтИсп.ПланыОбменаБСП());
	
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
			
		НаборЗаписей = ОбменДаннымиСлужебный.СоздатьНаборЗаписейРегистраСведений(Новый Структура("ИмяПланаОбмена", Выборка.ИмяПланаОбмена),
			"ПравилаДляОбменаДанными");
		НаборЗаписей.Записать();
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ПолучитьСценарииОбменаДаннымиДляМонитора(МенеджерВременныхТаблиц)
	
	Запрос = Новый Запрос;
	
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		ТекстЗапроса =
			"ВЫБРАТЬ
			|	СценарииОбменовДаннымиНастройкиОбмена.УзелИнформационнойБазы КАК УзелИнформационнойБазы
			|ПОМЕСТИТЬ СценарииСинхронизацииДанных
			|ИЗ
			|	Справочник.СценарииОбменовДанными.НастройкиОбмена КАК СценарииОбменовДаннымиНастройкиОбмена
			|ГДЕ
			|	СценарииОбменовДаннымиНастройкиОбмена.Ссылка.ИспользоватьРегламентноеЗадание = ИСТИНА
			|
			|СГРУППИРОВАТЬ ПО
			|	СценарииОбменовДаннымиНастройкиОбмена.УзелИнформационнойБазы";
					
	Иначе
		
		ТекстЗапроса =
			"ВЫБРАТЬ
			|	НЕОПРЕДЕЛЕНО КАК УзелИнформационнойБазы
			|ПОМЕСТИТЬ СценарииСинхронизацииДанных";
		
	КонецЕсли;
	
	Запрос.Текст = ТекстЗапроса;
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	Запрос.Выполнить();
	
КонецПроцедуры

Процедура ПолучитьПланыОбменаДляМонитора(МенеджерВременныхТаблиц, ПланыОбменаМассив, Знач ДополнительныеСвойстваПланаОбмена)
	
	Запрос = Новый Запрос;
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	
	// Логика по формированию запроса вынесена в отдельную функцию.
	ПараметрыЗапроса = ПараметрыЗапросаПланыОбменаДляМонитора();
	ПараметрыЗапроса.ПланыОбменаМассив                 = ПланыОбменаМассив;
	ПараметрыЗапроса.ДополнительныеСвойстваПланаОбмена = ДополнительныеСвойстваПланаОбмена;
	ПараметрыЗапроса.РезультатВоВременнуюТаблицу       = Истина;
	Запрос.Текст = ТекстЗапросаПланыОбменаДляМонитора(ПараметрыЗапроса);
	Запрос.Выполнить();
	
КонецПроцедуры

// Функция для объявления структуры параметров функции ТекстЗапросаПланыОбменаДляМонитора.
//
// Параметры:
//   Нет.
//
// Возвращаемое значение:
//   Структура.
//
Функция ПараметрыЗапросаПланыОбменаДляМонитора()
	
	ПараметрыЗапроса = Новый Структура;
	ПараметрыЗапроса.Вставить("ПланыОбменаМассив",                 Новый Массив);
	ПараметрыЗапроса.Вставить("ДополнительныеСвойстваПланаОбмена", "");
	ПараметрыЗапроса.Вставить("РезультатВоВременнуюТаблицу",       Ложь);
	
	Возврат ПараметрыЗапроса;
	
КонецФункции

// Возвращает текст запроса для получения данных узлов планов обмена.
//
// Параметры:
//   ПараметрыЗапроса - см. ПараметрыЗапросаПланыОбменаДляМонитора
//   ИсключитьПланыОбменаАвтономнойРаботы  - Булево - если Истина, то из текста запроса исключаются планы обмена
//                                                    автономной работы.
//
// Возвращаемое значение:
//   Строка - результирующий текст запроса.
//
Функция ТекстЗапросаПланыОбменаДляМонитора(ПараметрыЗапроса = Неопределено, ИсключитьПланыОбменаАвтономнойРаботы = Истина) Экспорт
	
	Если ПараметрыЗапроса = Неопределено Тогда
		ПараметрыЗапроса = ПараметрыЗапросаПланыОбменаДляМонитора();
	КонецЕсли;
	
	ПланыОбменаМассив                 = ПараметрыЗапроса.ПланыОбменаМассив;
	ДополнительныеСвойстваПланаОбмена = ПараметрыЗапроса.ДополнительныеСвойстваПланаОбмена;
	РезультатВоВременнуюТаблицу       = ПараметрыЗапроса.РезультатВоВременнуюТаблицу;
	
	Если Не ЗначениеЗаполнено(ПланыОбменаМассив) Тогда
		ПланыОбменаМассив = ОбменДаннымиПовтИсп.ПланыОбменаБСП();
	КонецЕсли;
	
	ПланыОбменаМетода = ФильтрПлановОбменаПоПризнакуРазделенияДанных(ПланыОбменаМассив);
	
	Если ОбменДаннымиПовтИсп.АвтономнаяРаботаПоддерживается()
		И ИсключитьПланыОбменаАвтономнойРаботы Тогда
		
		// Для плана обмена автономной работы используется отдельный монитор.
		ПланыОбменаМетода = ФильтрПлановОбменаПоПризнакуАвтономнойРаботы(ПланыОбменаМетода);
		
	КонецЕсли;
	
	ДополнительныеСвойстваПланаОбменаСтрокой = ?(ПустаяСтрока(ДополнительныеСвойстваПланаОбмена), "", ДополнительныеСвойстваПланаОбмена + ", ");
	
	СекцияОбъединения = "
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|";
	
	ШаблонЗапроса = СекцияОбъединения + 
	"//////////////////////////////////////////////////////// {&ИмяТаблицыПланаОбмена}
	|ВЫБРАТЬ
	|
	|	&ДополнительныеСвойстваПланаОбмена,
	|
	|	Ссылка                      КАК УзелИнформационнойБазы,
	|	Наименование                КАК Наименование,
	|	""&ИмяПланаОбменаСиноним"" КАК ИмяПланаОбмена
	|ИЗ
	|	&ИмяТаблицыПланаОбмена
	|ГДЕ
	|	     НЕ ЭтотУзел
	|	И НЕ ПометкаУдаления
	|";
	
	ТекстЗапроса = "";
	
	Если ПланыОбменаМетода.Количество() > 0 Тогда
		
		ШаблонИмениТаблицыПланаОбмена = "ПланОбмена.%1";
		
		Для Каждого ИмяПланаОбмена Из ПланыОбменаМетода Цикл
			
			ИмяТаблицыПланаОбмена = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонИмениТаблицыПланаОбмена, ИмяПланаОбмена);
			
			ТекстЗапросаДляПланаОбмена = СтрЗаменить(ШаблонЗапроса,              "&ИмяТаблицыПланаОбмена", ИмяТаблицыПланаОбмена);
			ТекстЗапросаДляПланаОбмена = СтрЗаменить(ТекстЗапросаДляПланаОбмена, "&ИмяПланаОбменаСиноним", Метаданные.ПланыОбмена[ИмяПланаОбмена].Синоним);
			ТекстЗапросаДляПланаОбмена = СтрЗаменить(ТекстЗапросаДляПланаОбмена, "&ДополнительныеСвойстваПланаОбмена,", ДополнительныеСвойстваПланаОбменаСтрокой);
			
			// Удаляем литерал объединения для первой таблицы.
			Если ПустаяСтрока(ТекстЗапроса) Тогда
				
				ТекстЗапросаДляПланаОбмена = СтрЗаменить(ТекстЗапросаДляПланаОбмена, "ОБЪЕДИНИТЬ ВСЕ", "");
				
			КонецЕсли;
			
			ТекстЗапроса = ТекстЗапроса + ТекстЗапросаДляПланаОбмена;
			
		КонецЦикла;
		
	Иначе
		
		ДополнительныеСвойстваБезИсточникаДанныхСтрокой = "";
		
		Если Не ПустаяСтрока(ДополнительныеСвойстваПланаОбмена) Тогда
			
			ДополнительныеСвойства = СтрРазделить(ДополнительныеСвойстваПланаОбмена, ",");
			
			ДополнительныеСвойстваБезИсточникаДанных = Новый Массив;
			
			Для Каждого Свойство Из ДополнительныеСвойства Цикл
				
				ДополнительныеСвойстваБезИсточникаДанных.Добавить(СтрЗаменить("Неопределено КАК [Свойство]", "[Свойство]", Свойство));
				
			КонецЦикла;
			
			ДополнительныеСвойстваБезИсточникаДанныхСтрокой = СтрСоединить(ДополнительныеСвойстваБезИсточникаДанных, ",") + ", ";
			
		КонецЕсли;
		
		ТекстЗапроса = "
		|ВЫБРАТЬ
		|
		|	&ДополнительныеСвойстваБезИсточникаДанныхСтрокой,
		|
		|	Неопределено КАК УзелИнформационнойБазы,
		|	Неопределено КАК Наименование,
		|	Неопределено КАК ИмяПланаОбмена
		|";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДополнительныеСвойстваБезИсточникаДанныхСтрокой,", ДополнительныеСвойстваБезИсточникаДанныхСтрокой);
		
	КонецЕсли;
	
	ТекстЗапросаРезультат = "
	|//////////////////////////////////////////////////////// {ПланыОбменаКонфигурации}
	|ВЫБРАТЬ
	|
	|	&ДополнительныеСвойстваПланаОбмена,
	|
	|	УзелИнформационнойБазы,
	|	Наименование,
	|	ИмяПланаОбмена
	|ПОМЕСТИТЬ ПланыОбменаКонфигурации
	|ИЗ
	|	&ТекстЗапроса КАК ВложенныйЗапрос
	|;
	|";
	
	Если РезультатВоВременнуюТаблицу <> Истина Тогда
		
		ТекстЗапросаРезультат = СтрЗаменить(ТекстЗапросаРезультат, "ПОМЕСТИТЬ ПланыОбменаКонфигурации", "");
		
	КонецЕсли;
	
	ОбернутыйТекстЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("(%1)", ТекстЗапроса);
	ТекстЗапросаРезультат = СтрЗаменить(ТекстЗапросаРезультат, "&ТекстЗапроса", ОбернутыйТекстЗапроса);
	
	ТекстЗапросаРезультат = СтрЗаменить(ТекстЗапросаРезультат, "&ДополнительныеСвойстваПланаОбмена,", ДополнительныеСвойстваПланаОбменаСтрокой);
	
	Возврат ТекстЗапросаРезультат;
	
КонецФункции

Процедура ПолучитьСостоянияОбменовДанными(МенеджерВременныхТаблиц)
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных()
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
		МодульОбменДаннымиВМоделиСервиса.ПолучитьСостоянияОбменовДанными(МенеджерВременныхТаблиц);
	Иначе
		Запрос = Новый Запрос(
		"ВЫБРАТЬ
		|	СостоянияОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	СостоянияОбменовДанными.ДатаНачала КАК ДатаНачала,
		|	СостоянияОбменовДанными.ДатаОкончания КАК ДатаОкончания,
		|	ВЫБОР
		|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Предупреждение_СообщениеОбменаБылоРанееПринято)
		|				ИЛИ СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями)
		|			ТОГДА 2
		|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Выполнено)
		|			ТОГДА ВЫБОР
		|					КОГДА ЕСТЬNULL(КоличествоПроблем.Количество, 0) > 0
		|						ТОГДА 2
		|					ИНАЧЕ 0
		|				КОНЕЦ
		|		ИНАЧЕ 1
		|	КОНЕЦ КАК РезультатВыполненияОбмена
		|ПОМЕСТИТЬ СостоянияОбменовДаннымиЗагрузка
		|ИЗ
		|	РегистрСведений.СостоянияОбменовДанными КАК СостоянияОбменовДанными
		|		ЛЕВОЕ СОЕДИНЕНИЕ КоличествоПроблем КАК КоличествоПроблем
		|		ПО СостоянияОбменовДанными.УзелИнформационнойБазы = КоличествоПроблем.УзелИнформационнойБазы
		|			И СостоянияОбменовДанными.ДействиеПриОбмене = КоличествоПроблем.ДействиеПриОбмене
		|ГДЕ
		|	СостоянияОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	СостоянияОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	СостоянияОбменовДанными.ДатаНачала КАК ДатаНачала,
		|	СостоянияОбменовДанными.ДатаОкончания КАК ДатаОкончания,
		|	ВЫБОР
		|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями)
		|			ТОГДА 2
		|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Выполнено)
		|			ТОГДА ВЫБОР
		|					КОГДА ЕСТЬNULL(КоличествоПроблем.Количество, 0) > 0
		|						ТОГДА 2
		|					ИНАЧЕ 0
		|				КОНЕЦ
		|		ИНАЧЕ 1
		|	КОНЕЦ КАК РезультатВыполненияОбмена
		|ПОМЕСТИТЬ СостоянияОбменовДаннымиВыгрузка
		|ИЗ
		|	РегистрСведений.СостоянияОбменовДанными КАК СостоянияОбменовДанными
		|		ЛЕВОЕ СОЕДИНЕНИЕ КоличествоПроблем КАК КоличествоПроблем
		|		ПО СостоянияОбменовДанными.УзелИнформационнойБазы = КоличествоПроблем.УзелИнформационнойБазы
		|			И СостоянияОбменовДанными.ДействиеПриОбмене = КоличествоПроблем.ДействиеПриОбмене
		|ГДЕ
		|	СостоянияОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	СостоянияУспешныхОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	СостоянияУспешныхОбменовДанными.ДатаОкончания КАК ДатаОкончания
		|ПОМЕСТИТЬ СостоянияУспешныхОбменовДаннымиЗагрузка
		|ИЗ
		|	РегистрСведений.СостоянияУспешныхОбменовДанными КАК СостоянияУспешныхОбменовДанными
		|ГДЕ
		|	СостоянияУспешныхОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	СостоянияУспешныхОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	СостоянияУспешныхОбменовДанными.ДатаОкончания КАК ДатаОкончания
		|ПОМЕСТИТЬ СостоянияУспешныхОбменовДаннымиВыгрузка
		|ИЗ
		|	РегистрСведений.СостоянияУспешныхОбменовДанными КАК СостоянияУспешныхОбменовДанными
		|ГДЕ
		|	СостоянияУспешныхОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)");
		
		Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
		Запрос.Выполнить();
	КонецЕсли;
	
КонецПроцедуры

Процедура ПолучитьРезультатыОбменаДляМонитора(МенеджерВременныхТаблиц)
	
	Запрос = Новый Запрос;
	
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		ТекстЗапросаРезультат = 
		"ВЫБРАТЬ
		|	РезультатыОбменаДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	ВЫБОР
		|		КОГДА РезультатыОбменаДанными.ТипПроблемы В (ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.НепроведенныйДокумент), ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.НезаполненныеРеквизиты), ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриПолученииДанных))
		|			ТОГДА ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
		|		КОГДА РезультатыОбменаДанными.ТипПроблемы В (ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.АдминистративнаяОшибкаПриложения), ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриОтправкеДанных), ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.ОшибкаПроверкиСконвертированногоОбъекта))
		|			ТОГДА ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)
		|		ИНАЧЕ НЕОПРЕДЕЛЕНО
		|	КОНЕЦ КАК ДействиеПриОбмене,
		|	КОЛИЧЕСТВО(РАЗЛИЧНЫЕ РезультатыОбменаДанными.ПроблемныйОбъект) КАК Количество
		|ПОМЕСТИТЬ КоличествоПроблем
		|ИЗ
		|	РегистрСведений.РезультатыОбменаДанными КАК РезультатыОбменаДанными
		|ГДЕ
		|	РезультатыОбменаДанными.Пропущена = ЛОЖЬ
		|
		|СГРУППИРОВАТЬ ПО
		|	РезультатыОбменаДанными.УзелИнформационнойБазы,
		|	ВЫБОР
		|		КОГДА РезультатыОбменаДанными.ТипПроблемы В (ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.НепроведенныйДокумент), ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.НезаполненныеРеквизиты), ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриПолученииДанных))
		|			ТОГДА ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
		|		КОГДА РезультатыОбменаДанными.ТипПроблемы В (ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.АдминистративнаяОшибкаПриложения), ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриОтправкеДанных), ЗНАЧЕНИЕ(Перечисление.ТипыПроблемОбменаДанными.ОшибкаПроверкиСконвертированногоОбъекта))
		|			ТОГДА ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)
		|		ИНАЧЕ НЕОПРЕДЕЛЕНО
		|	КОНЕЦ";
		
	Иначе
		
		ТекстЗапросаРезультат = 
		"ВЫБРАТЬ
		|	НЕОПРЕДЕЛЕНО КАК УзелИнформационнойБазы,
		|	НЕОПРЕДЕЛЕНО КАК ДействиеПриОбмене,
		|	НЕОПРЕДЕЛЕНО КАК Количество
		|ПОМЕСТИТЬ КоличествоПроблем";
		
	КонецЕсли;
	
	Запрос.Текст = ТекстЗапросаРезультат;
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	Запрос.Выполнить();
	
КонецПроцедуры

Процедура ПолучитьСообщенияДляСопоставленияДанных(МенеджерВременныхТаблиц)
	
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Если ОбщегоНазначения.РазделениеВключено()
			И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
			МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
			МодульОбменДаннымиВМоделиСервиса.ПолучитьСообщенияДляСопоставленияДанных(МенеджерВременныхТаблиц);
		Иначе
			Запрос = Новый Запрос(
			"ВЫБРАТЬ
			|	ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
			|	ВЫБОР
			|		КОГДА КОЛИЧЕСТВО(ОбщиеНастройкиУзловИнформационныхБаз.СообщениеДляСопоставленияДанных) > 0
			|			ТОГДА ИСТИНА
			|		ИНАЧЕ ЛОЖЬ
			|	КОНЕЦ КАК ПолученоСообщениеДляСопоставленияДанных,
			|	МАКСИМУМ(СообщенияОбменаДанными.ДатаЗакладкиСообщения) КАК ДатаЗакладкиПоследнегоСообщения
			|ПОМЕСТИТЬ СообщенияДляСопоставленияДанных
			|ИЗ
			|	РегистрСведений.ОбщиеНастройкиУзловИнформационныхБаз КАК ОбщиеНастройкиУзловИнформационныхБаз
			|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СообщенияОбменаДанными КАК СообщенияОбменаДанными
			|		ПО (СообщенияОбменаДанными.ИдентификаторСообщения = ОбщиеНастройкиУзловИнформационныхБаз.СообщениеДляСопоставленияДанных)
			|
			|СГРУППИРОВАТЬ ПО
			|	ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы");
			
			Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
			Запрос.Выполнить();
		КонецЕсли;
	Иначе
		Запрос = Новый Запрос(
		"ВЫБРАТЬ
		|	NULL КАК УзелИнформационнойБазы,
		|	NULL КАК ПолученоСообщениеДляСопоставленияДанных,
		|	NULL КАК ДатаЗакладкиПоследнегоСообщения
		|ПОМЕСТИТЬ СообщенияДляСопоставленияДанных");
		
		Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
		Запрос.Выполнить();
	КонецЕсли;
	
КонецПроцедуры

Функция ПланыОбменаСПравиламиИзФайла()
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ПравилаДляОбменаДанными.ИмяПланаОбмена
	|ИЗ
	|	РегистрСведений.ПравилаДляОбменаДанными КАК ПравилаДляОбменаДанными
	|ГДЕ
	|	ПравилаДляОбменаДанными.ИсточникПравил = &ИсточникПравил";
	
	Запрос.УстановитьПараметр("ИсточникПравил", Перечисления.ИсточникиПравилДляОбменаДанными.Файл);
	Результат = Запрос.Выполнить().Выгрузить();
	
	Возврат Результат.Количество();
	
КонецФункции

Процедура ПроверитьВозможностьВнешнегоСоединения()
	
	Если ОбщегоНазначения.ЭтоLinuxСервер() Тогда
		
		ВызватьИсключение НСтр("ru = 'Синхронизация данных через прямое подключение на сервере под управлением ОС Linux недоступно.
			|Для синхронизации данных через прямое подключение используйте ОС Windows.'");
			
	КонецЕсли;
	
КонецПроцедуры

// Заполняет список значений доступными видами транспорта для узла плана обмена.
//
Процедура ЗаполнитьСписокВыбораДоступнымиВидамиТранспорта(УзелИнформационнойБазы, ЭлементФормы, Отбор = Неопределено) Экспорт
	
	ОтборЗадан = (Отбор <> Неопределено);
	
	ИспользуемыеТранспорты = ОбменДаннымиПовтИсп.ИспользуемыеТранспортыСообщенийОбмена(УзелИнформационнойБазы);
	
	ЭлементФормы.СписокВыбора.Очистить();
	
	Для Каждого Элемент Из ИспользуемыеТранспорты Цикл
		
		Если ОтборЗадан Тогда
			
			Если Отбор.Найти(Элемент) <> Неопределено Тогда
				
				ЭлементФормы.СписокВыбора.Добавить(Элемент, Строка(Элемент));
				
			КонецЕсли;
			
		Иначе
			
			ЭлементФормы.СписокВыбора.Добавить(Элемент, Строка(Элемент));
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Фиксирует состояние обмена данными в регистре сведений СостоянияОбменовДанными.
//
// Параметры:
//  СтруктураНастроекОбмена - Структура - структура со всеми необходимыми данными и объектами для выполнения обмена.
// 
Процедура ЗафиксироватьЗавершениеОбменаВРегистреСведений(СтруктураНастроекОбмена)
	
	// Создаем структуру для новой записи в РС.
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("УзелИнформационнойБазы",    СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураЗаписи.Вставить("ДействиеПриОбмене",         СтруктураНастроекОбмена.ДействиеПриОбмене);
	
	СтруктураЗаписи.Вставить("РезультатВыполненияОбмена", СтруктураНастроекОбмена.РезультатВыполненияОбмена);
	СтруктураЗаписи.Вставить("ДатаНачала",                СтруктураНастроекОбмена.ДатаНачала);
	СтруктураЗаписи.Вставить("ДатаОкончания",             СтруктураНастроекОбмена.ДатаОкончания);
	
	РегистрыСведений.СостоянияОбменовДанными.ДобавитьЗапись(СтруктураЗаписи);
	
КонецПроцедуры

Процедура ЗафиксироватьУспешныйОбменДаннымиВРегистреСведений(СтруктураНастроекОбмена)
	
	// Создаем структуру для новой записи в РС.
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("УзелИнформационнойБазы", СтруктураНастроекОбмена.УзелИнформационнойБазы);
	СтруктураЗаписи.Вставить("ДействиеПриОбмене",      СтруктураНастроекОбмена.ДействиеПриОбмене);
	СтруктураЗаписи.Вставить("ДатаОкончания",          СтруктураНастроекОбмена.ДатаОкончания);
	
	РегистрыСведений.СостоянияУспешныхОбменовДанными.ДобавитьЗапись(СтруктураЗаписи);
	
КонецПроцедуры

Процедура ЗаписьЖурналаРегистрацииНачалаОбменаДанными(СтруктураНастроекОбмена) Экспорт
	
	СтрокаСообщения = НСтр("ru = 'Начало процесса обмена данными для узла %1'", ОбщегоНазначения.КодОсновногоЯзыка());
	СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, СтруктураНастроекОбмена.УзелИнформационнойБазыНаименование);
	ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщения, СтруктураНастроекОбмена);
	
КонецПроцедуры

Процедура ЗаписатьСобытиеПолученияДанных(Знач УзелИнформационнойБазы, Знач Комментарий, Знач ЭтоОшибка = Ложь)
	
	Уровень = ?(ЭтоОшибка, УровеньЖурналаРегистрации.Ошибка, УровеньЖурналаРегистрации.Информация);
	
	КлючСообщенияЖурналаРегистрации = КлючСообщенияЖурналаРегистрации(УзелИнформационнойБазы, Перечисления.ДействияПриОбмене.ЗагрузкаДанных);
	
	ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, Уровень,,, Комментарий);
	
КонецПроцедуры

Процедура ФормаНастройкиУзлаОбработчикПриСозданииНаСервере(Форма, ИмяРеквизитаФормы)
	
	РеквизитыФормы = ИменаРеквизитовФормы(Форма);
	
	Для Каждого НастройкаОтбора Из Форма[ИмяРеквизитаФормы] Цикл
		
		Ключ = НастройкаОтбора.Ключ;
		
		Если РеквизитыФормы.Найти(Ключ) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если ТипЗнч(Форма[Ключ]) = Тип("ДанныеФормыКоллекция") Тогда
			
			Таблица = Новый ТаблицаЗначений;
			
			СтруктураТабличнойЧасти = Форма.Параметры[ИмяРеквизитаФормы][Ключ];
			
			Для Каждого Элемент Из СтруктураТабличнойЧасти Цикл
				
				Пока Таблица.Количество() < Элемент.Значение.Количество() Цикл
					Таблица.Добавить();
				КонецЦикла;
				
				Таблица.Колонки.Добавить(Элемент.Ключ);
				
				Таблица.ЗагрузитьКолонку(Элемент.Значение, Элемент.Ключ);
				
			КонецЦикла;
			
			Форма[Ключ].Загрузить(Таблица);
			
		Иначе
			
			Форма[Ключ] = Форма.Параметры[ИмяРеквизитаФормы][Ключ];
			
		КонецЕсли;
		
		Форма[ИмяРеквизитаФормы][Ключ] = Форма.Параметры[ИмяРеквизитаФормы][Ключ];
		
	КонецЦикла;
	
КонецПроцедуры

Функция ИменаРеквизитовФормы(Форма)
	
	// Возвращаемое значение функции.
	Результат = Новый Массив;
	
	Для Каждого РеквизитФормы Из Форма.ПолучитьРеквизиты() Цикл
		
		Результат.Добавить(РеквизитФормы.Имя);
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Распаковывает файл архива ZIP в указанный каталог; Извлекает все файлы архива.
//
// Параметры:
//  ПолноеИмяФайлаАрхива  - Строка - имя файла архива, который необходимо распаковать.
//  ПутьРаспаковкиФайлов  - Строка - путь по которому необходимо распаковать файлы.
//  ПарольАрхива          - Строка - пароль для распаковки архива. По умолчанию пустая строка.
// 
// Возвращаемое значение:
//  Результат - Булево - Истина, если успешно, Ложь, если нет.
//
Функция РаспаковатьZipФайл(Знач ПолноеИмяФайлаАрхива, Знач ПутьРаспаковкиФайлов, Знач ПарольАрхива = "") Экспорт
	
	Результат = Истина;
	
	Архиватор = Неопределено;
	Попытка
		Архиватор = Новый ЧтениеZipФайла(ПолноеИмяФайлаАрхива, ПарольАрхива);
		Архиватор.ИзвлечьВсе(ПутьРаспаковкиФайлов, РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
	Исключение
		ИнформацияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка при распаковке файлов архива ""%1"" в каталог ""%2"" по причине:
			|%3'"),
			ПолноеИмяФайлаАрхива,
			ПутьРаспаковкиФайлов,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(),
			УровеньЖурналаРегистрации.Ошибка, , , ИнформацияОбОшибке);
		
		Результат = Ложь;
	КонецПопытки;
	
	Если Архиватор <> Неопределено Тогда
		Архиватор.Закрыть();
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Запаковывает указанный каталог в файл архива ZIP.
//
// Параметры:
//  ПолноеИмяФайлаАрхива  - Строка - имя файла архива, в который необходимо запаковать.
//  МаскаУпаковкиФайлов    - Строка - имя файла, помещаемого в архив, или маска.
//			Недопустимо использование в именах файлов и папок букв национальных алфавитов, которые при 
//			преобразовании из символов UNICODE в узкие символы могут быть преобразованы с потерей информации. 
//			Рекомендуется использовать в именах файлов и папок символы латинского алфавита. 
//  ПарольАрхива          - Строка - пароль для архива. По умолчанию пустая строка.
// 
// Возвращаемое значение:
//  Результат - Булево - Истина, если успешно, Ложь, если нет.
//
Функция ЗапаковатьВZipФайл(Знач ПолноеИмяФайлаАрхива, Знач МаскаУпаковкиФайлов, Знач ПарольАрхива = "") Экспорт
	
	// Возвращаемое значение функции.
	Результат = Истина;
	
	Попытка
		
		Архиватор = Новый ЗаписьZipФайла(ПолноеИмяФайлаАрхива, ПарольАрхива);
		
	Исключение
		Архиватор = Неопределено;
		СообщитьОбОшибке(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат Ложь;
	КонецПопытки;
	
	Попытка
		
		Архиватор.Добавить(МаскаУпаковкиФайлов, РежимСохраненияПутейZIP.НеСохранятьПути);
		Архиватор.Записать();
		
	Исключение
		ИнформацияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка при запаковке файлов ""%1"" в архив ""%2"" по причине:
			|%3'"),
			МаскаУпаковкиФайлов,
			ПолноеИмяФайлаАрхива,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(),
			УровеньЖурналаРегистрации.Ошибка, , , ИнформацияОбОшибке);
		
		Результат = Ложь;
	КонецПопытки;
	
	Архиватор = Неопределено;
	
	Возврат Результат;
	
КонецФункции

// Возвращает количество записей в таблице базы данных.
//
// Параметры:
//  ИмяТаблицы - Строка - полное имя таблицы базы данных. Например: "Справочник.Контрагенты.Заказы".
// 
// Возвращаемое значение:
//  Число - количество записей в таблице базы данных.
//
Функция КоличествоЗаписейВТаблицеБазыДанных(Знач ИмяТаблицы) Экспорт
	
	ТекстЗапроса = "
	|ВЫБРАТЬ
	|	Количество(*) КАК Количество
	|ИЗ
	|	#ИмяТаблицы
	|";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяТаблицы", ИмяТаблицы);
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	
	Выборка = Запрос.Выполнить().Выбрать();
	Выборка.Следующий();
	
	Возврат Выборка["Количество"];
	
КонецФункции

// Возвращает количество записей во временной таблице базы данных.
//
// Параметры:
//  ИмяТаблицы - Строка - имя таблицы. Например: "ВременнаяТаблица1".
//  МенеджерВременныхТаблиц - менеджер временных таблиц, который содержит указатель на временную таблицу ИмяТаблицы.
// 
// Возвращаемое значение:
//  Число - количество записей в таблице базы данных.
//
Функция КоличествоЗаписейВоВременнойТаблицеБазыДанных(Знач ИмяТаблицы, МенеджерВременныхТаблиц) Экспорт
	
	ТекстЗапроса = "
	|ВЫБРАТЬ
	|	Количество(*) КАК Количество
	|ИЗ
	|	#ИмяТаблицы
	|";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяТаблицы", ИмяТаблицы);
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	
	Выборка = Запрос.Выполнить().Выбрать();
	Выборка.Следующий();
	
	Возврат Выборка["Количество"];
	
КонецФункции

// Возвращает ключ сообщения журнала регистрации.
//
Функция КлючСообщенияЖурналаРегистрации(УзелИнформационнойБазы, ДействиеПриОбмене) Экспорт
	
	ИмяПланаОбмена     = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
	
	КлючСообщения = НСтр("ru = 'Обмен данными.[ИмяПланаОбмена].[ДействиеПриОбмене]'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	
	КлючСообщения = СтрЗаменить(КлючСообщения, "[ИмяПланаОбмена]",    ИмяПланаОбмена);
	КлючСообщения = СтрЗаменить(КлючСообщения, "[ДействиеПриОбмене]", ДействиеПриОбмене);
	
	Возврат КлючСообщения;
	
КонецФункции

// Возвращает признак того, что реквизит входит в подмножество стандартных реквизитов.
// 
// Параметры:
//   СтандартныеРеквизиты - ОписанияСтандартныхРеквизитов - коллекция стандартных реквизитов.
//   ИмяРеквизита - Строка - имя проверяемого реквизита.
// 
// Возвращаемое значение:
//   Булево - Истина, если заданный реквизит является стандартным.
//
Функция ЭтоСтандартныйРеквизит(СтандартныеРеквизиты, ИмяРеквизита) Экспорт
	
	Для Каждого Реквизит Из СтандартныеРеквизиты Цикл
		
		Если Реквизит.Имя = ИмяРеквизита Тогда
			
			Возврат Истина;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

// Формирует и возвращает ключ таблицы данных.
// Ключ таблицы используется для выборочной загрузки данных из сообщения обмена по заданному ключу.
//
Функция КлючТаблицыДанных(Знач ТипИсточника, Знач ТипПриемника, Знач ЭтоУдалениеОбъекта) Экспорт
	
	Возврат ТипИсточника + "#" + ТипПриемника + "#" + Строка(ЭтоУдалениеОбъекта);
	
КонецФункции

Функция НадоВыполнитьОбработчик(Объект, Ссылка, ИмяСвойства)
	
	НомерПослеОбработки = Объект[ИмяСвойства];
	
	НомерПередОбработкой = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, ИмяСвойства);
	
	НомерПередОбработкой = ?(НомерПередОбработкой = Неопределено, 0, НомерПередОбработкой);
	
	Возврат НомерПередОбработкой <> НомерПослеОбработки;
	
КонецФункции

Функция ЗаполнитьПараметрыПодключенияВнешнегоСоединения(НастройкиТранспорта)
	
	ПараметрыПодключения = ОбщегоНазначенияКлиентСервер.СтруктураПараметровДляУстановкиВнешнегоСоединения();
	
	ПараметрыПодключения.ВариантРаботыИнформационнойБазы             = НастройкиТранспорта.COMВариантРаботыИнформационнойБазы;
	ПараметрыПодключения.КаталогИнформационнойБазы                   = НастройкиТранспорта.COMКаталогИнформационнойБазы;
	ПараметрыПодключения.ИмяСервера1СПредприятия                     = НастройкиТранспорта.COMИмяСервера1СПредприятия;
	ПараметрыПодключения.ИмяИнформационнойБазыНаСервере1СПредприятия = НастройкиТранспорта.COMИмяИнформационнойБазыНаСервере1СПредприятия;
	ПараметрыПодключения.АутентификацияОперационнойСистемы           = НастройкиТранспорта.COMАутентификацияОперационнойСистемы;
	ПараметрыПодключения.ИмяПользователя                             = НастройкиТранспорта.COMИмяПользователя;
	ПараметрыПодключения.ПарольПользователя                          = НастройкиТранспорта.COMПарольПользователя;
	
	Возврат ПараметрыПодключения;
КонецФункции

Функция ДобавитьЛитералКИмениФайла(Знач ПолноеИмяФайла, Знач Литерал)
	
	Если ПустаяСтрока(ПолноеИмяФайла) Тогда
		Возврат "";
	КонецЕсли;
	
	ИмяФайлаБезРасширения = Сред(ПолноеИмяФайла, 1, СтрДлина(ПолноеИмяФайла) - 4);
	
	Расширение = Прав(ПолноеИмяФайла, 3);
	
	Результат = "[ИмяФайлаБезРасширения]_[Литерал].[Расширение]";
	
	Результат = СтрЗаменить(Результат, "[ИмяФайлаБезРасширения]", ИмяФайлаБезРасширения);
	Результат = СтрЗаменить(Результат, "[Литерал]",               Литерал);
	Результат = СтрЗаменить(Результат, "[Расширение]",            Расширение);
	
	Возврат Результат;
КонецФункции

Функция НаименованиеПредопределенногоУзлаПланаОбмена(ИмяПланаОбмена) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ОбменДаннымиПовтИсп.ПолучитьЭтотУзелПланаОбмена(ИмяПланаОбмена), "Наименование");
КонецФункции

Процедура ОбработчикПриВыгрузкеДанныхБСП(
		Обработчики,
		ПараметрыВыполнения,
		СтандартнаяОбработка,
		ДанныеСообщения,
		КоличествоОтправленныхОбъектов)
	
	Для Каждого Обработчик Из Обработчики Цикл
		
		Если Не СтандартнаяОбработка Тогда
			Прервать;
		КонецЕсли;
		
		КоличествоОтправленныхОбъектов = 0;
		
		Обработчик.ПриВыгрузкеДанных(СтандартнаяОбработка,
			ПараметрыВыполнения.УзелИнформационнойБазы,
			ПараметрыВыполнения.ИмяФайлаСообщенияОбмена,
			ДанныеСообщения,
			ПараметрыВыполнения.КоличествоЭлементовВТранзакции,
			ПараметрыВыполнения.КлючСообщенияЖурналаРегистрации,
			КоличествоОтправленныхОбъектов);
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ОбработчикПриЗагрузкеДанныхБСП(
		Обработчики,
		ПараметрыВыполнения,
		СтандартнаяОбработка,
		ДанныеСообщения,
		КоличествоПолученныхОбъектов)
	
	Для Каждого Обработчик Из Обработчики Цикл
		
		Если Не СтандартнаяОбработка Тогда
			Прервать;
		КонецЕсли;
		
		КоличествоПолученныхОбъектов = 0;
		
		Обработчик.ПриЗагрузкеДанных(СтандартнаяОбработка,
			ПараметрыВыполнения.УзелИнформационнойБазы,
			ПараметрыВыполнения.ИмяФайлаСообщенияОбмена,
			ДанныеСообщения,
			ПараметрыВыполнения.КоличествоЭлементовВТранзакции,
			ПараметрыВыполнения.КлючСообщенияЖурналаРегистрации,
			КоличествоПолученныхОбъектов);
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ЗафиксироватьЗавершениеОбменаСОшибкой(Знач УзелИнформационнойБазы, 
												Знач ДействиеПриОбмене, 
												Знач ДатаНачала, 
												Знач СтрокаСообщенияОбОшибке) Экспорт
	
	Если ТипЗнч(ДействиеПриОбмене) = Тип("Строка") Тогда
		
		ДействиеПриОбмене = Перечисления.ДействияПриОбмене[ДействиеПриОбмене];
		
	КонецЕсли;
	
	СтруктураНастроекОбмена = Новый Структура;
	СтруктураНастроекОбмена.Вставить("УзелИнформационнойБазы", УзелИнформационнойБазы);
	СтруктураНастроекОбмена.Вставить("РезультатВыполненияОбмена", Перечисления.РезультатыВыполненияОбмена.Ошибка);
	СтруктураНастроекОбмена.Вставить("ДействиеПриОбмене", ДействиеПриОбмене);
	СтруктураНастроекОбмена.Вставить("КоличествоОбъектовОбработано", 0);
	СтруктураНастроекОбмена.Вставить("КлючСообщенияЖурналаРегистрации", КлючСообщенияЖурналаРегистрации(УзелИнформационнойБазы, ДействиеПриОбмене));
	СтруктураНастроекОбмена.Вставить("ДатаНачала", ДатаНачала);
	СтруктураНастроекОбмена.Вставить("ДатаОкончания", ТекущаяДатаСеанса());
	СтруктураНастроекОбмена.Вставить("ЭтоОбменВРИБ", ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(УзелИнформационнойБазы));
	
	ЗаписьЖурналаРегистрацииОбменаДанными(СтрокаСообщенияОбОшибке, СтруктураНастроекОбмена, Истина);
	
	ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
	
КонецПроцедуры

// Проверяет наличие указанных реквизитов в форме.
// Если хотя бы один реквизит отсутствует, то вызывает исключение.
//
Процедура ПроверитьОбязательныеРеквизитыФормы(Форма, Знач Реквизиты)
	
	ОтсутствующиеРеквизиты = Новый Массив;
	
	РеквизитыФормы = ИменаРеквизитовФормы(Форма);
	
	Для Каждого Реквизит Из СтрРазделить(Реквизиты, ",") Цикл
		
		Реквизит = СокрЛП(Реквизит);
		
		Если РеквизитыФормы.Найти(Реквизит) = Неопределено Тогда
			
			ОтсутствующиеРеквизиты.Добавить(Реквизит);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Если ОтсутствующиеРеквизиты.Количество() > 0 Тогда
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Отсутствуют обязательные реквизиты формы настройки узла: %1'"),
			СтрСоединить(ОтсутствующиеРеквизиты, ","));
	КонецЕсли;
	
КонецПроцедуры

Процедура ВнешнееСоединениеОбновитьНастройкиОбменаДанными(Знач ИмяПланаОбмена, Знач КодУзла, Знач ЗначенияПоУмолчаниюНаУзле) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	УзелИнформационнойБазы = ПланыОбмена[ИмяПланаОбмена].НайтиПоКоду(КодУзла);
	
	Если Не ЗначениеЗаполнено(УзелИнформационнойБазы) Тогда
		Сообщение = НСтр("ru = 'Не найден узел плана обмена; имя плана обмена %1; код узла %2'");
		Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение, ИмяПланаОбмена, КодУзла);
		ВызватьИсключение Сообщение;
	КонецЕсли;
	
	ПомощникСозданияОбменаДанными = МодульПомощникСозданияОбменаДанными().Создать();
	ПомощникСозданияОбменаДанными.УзелИнформационнойБазы = УзелИнформационнойБазы;
	ПомощникСозданияОбменаДанными.ВнешнееСоединениеОбновитьНастройкиОбменаДанными(ПолучитьЗначенияНастройкиОтборов(ЗначенияПоУмолчаниюНаУзле));
	
КонецПроцедуры

Функция ИмяТаблицыИзПервогоРеквизитаТабличнойЧастиПланаОбмена(Знач ИмяПланаОбмена, Знач ИмяТабличнойЧасти)
	
	ТабличнаяЧасть = Метаданные.ПланыОбмена[ИмяПланаОбмена].ТабличныеЧасти[ИмяТабличнойЧасти];
	
	Для Каждого Реквизит Из ТабличнаяЧасть.Реквизиты Цикл
		
		Тип = Реквизит.Тип.Типы()[0];
		
		Если ОбщегоНазначения.ЭтоСсылка(Тип) Тогда
			
			Возврат Метаданные.НайтиПоТипу(Тип).ПолноеИмя();
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат "";
КонецФункции

Функция ВсеДанныеПланаОбменаКромеСправочников(Знач ИмяПланаОбмена)
	
	Если ТипЗнч(ИмяПланаОбмена) <> Тип("Строка") Тогда
		
		ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(ИмяПланаОбмена);
		
	КонецЕсли;
	
	Результат = Новый Массив;
	
	СоставПланаОбмена = Метаданные.ПланыОбмена[ИмяПланаОбмена].Состав;
	
	Для Каждого Элемент Из СоставПланаОбмена Цикл
		
		Если Не (ОбщегоНазначения.ЭтоСправочник(Элемент.Метаданные)
			ИЛИ ОбщегоНазначения.ЭтоПланВидовХарактеристик(Элемент.Метаданные)) Тогда
			
			Результат.Добавить(Элемент.Метаданные);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция НастройкиПараметровУчетаВСистемеУстановлены(Знач ИмяПланаОбмена, Знач Корреспондент, СообщениеОбОшибке)
	
	Если ТипЗнч(Корреспондент) = Тип("Строка") Тогда
		
		Если ПустаяСтрока(Корреспондент) Тогда
			Возврат Ложь;
		КонецЕсли;
		
		КорреспондентКод = Корреспондент;
		
		Корреспондент = ПланыОбмена[ИмяПланаОбмена].НайтиПоКоду(Корреспондент);
		
		Если Не ЗначениеЗаполнено(Корреспондент) Тогда
			Сообщение = НСтр("ru = 'Не найден узел плана обмена; имя плана обмена %1; код узла %2'");
			Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение, ИмяПланаОбмена, КорреспондентКод);
			ВызватьИсключение Сообщение;
		КонецЕсли;
		
	КонецЕсли;
	
	Отказ = Ложь;
	Если ЕстьАлгоритмМенеджераПланаОбмена("ОбработчикПроверкиПараметровУчета", ИмяПланаОбмена) Тогда
		УстановитьПривилегированныйРежим(Истина);
		ПланыОбмена[ИмяПланаОбмена].ОбработчикПроверкиПараметровУчета(Отказ, Корреспондент, СообщениеОбОшибке);
	КонецЕсли;
	
	Возврат Не Отказ;
КонецФункции

Функция ПолучитьПараметрыИнформационнойБазы(Знач ИмяПланаОбмена, Знач КодУзла, СообщениеОбОшибке) Экспорт
	
	Возврат ЗначениеВСтрокуВнутр(ПараметрыИнформационнойБазы(ИмяПланаОбмена, КодУзла, СообщениеОбОшибке));
	
КонецФункции

Функция ПолучитьПараметрыИнформационнойБазы_2_0_1_6(Знач ИмяПланаОбмена, Знач КодУзла, СообщениеОбОшибке) Экспорт
	
	Возврат ОбщегоНазначения.ЗначениеВСтрокуXML(ПараметрыИнформационнойБазы(ИмяПланаОбмена, КодУзла, СообщениеОбОшибке));
	
КонецФункции

Функция ПолучитьПараметрыИнформационнойБазы_3_0_2_2(Знач ИмяПланаОбмена, Знач КодУзла, СообщениеОбОшибке, 
	ДополнительныеПараметры = Неопределено) Экспорт
		
	ПараметрыИБ = ПараметрыИнформационнойБазы(ИмяПланаОбмена, КодУзла, СообщениеОбОшибке, ДополнительныеПараметры);
	
	Возврат ОбщегоНазначения.ЗначениеВСтрокуXML(ПараметрыИБ);
	
КонецФункции

Функция СвойстваОбъектаМетаданных(Знач ПолноеИмяТаблицы) Экспорт
	
	Результат = Новый Структура("Синоним, Иерархический");
	
	ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПолноеИмяТаблицы);
	
	ЗаполнитьЗначенияСвойств(Результат, ОбъектМетаданных);
	
	Возврат Результат;
КонецФункции

Функция ПолучитьОбъектыТаблицы(Знач ПолноеИмяТаблицы) Экспорт
	УстановитьПривилегированныйРежим(Истина);
	
	ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПолноеИмяТаблицы);
	
	Если ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных) Тогда
		
		Если ОбъектМетаданных.Иерархический Тогда
			Если ОбъектМетаданных.ВидИерархии = Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда
				Возврат ЭлементыИерархическогоСправочникаИерархияГруппИЭлементов(ПолноеИмяТаблицы);
			КонецЕсли;
			
			Возврат ЭлементыИерархическогоСправочникаИерархияЭлементов(ПолноеИмяТаблицы);
		КонецЕсли;
		
		Возврат ЭлементыНеиерархическогоСправочника(ПолноеИмяТаблицы);
		
	ИначеЕсли ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных) Тогда
		
		Если ОбъектМетаданных.Иерархический Тогда
			Возврат ЭлементыИерархическогоСправочникаИерархияГруппИЭлементов(ПолноеИмяТаблицы);
		КонецЕсли;
		
		Возврат ЭлементыНеиерархическогоСправочника(ПолноеИмяТаблицы);
		
	КонецЕсли;
	
	Возврат Неопределено;
КонецФункции

Функция ЭлементыИерархическогоСправочникаИерархияГруппИЭлементов(Знач ПолноеИмяТаблицы)
	
	ШаблонТекстаЗапроса =
		"ВЫБРАТЬ ПЕРВЫЕ 2000
		|	ПсевдонимТаблицыМетаданных.Ссылка,
		|	ПсевдонимТаблицыМетаданных.Представление,
		|	ВЫБОР
		|		КОГДА ПсевдонимТаблицыМетаданных.ЭтоГруппа
		|		И НЕ ПсевдонимТаблицыМетаданных.ПометкаУдаления
		|			ТОГДА 0
		|		КОГДА ПсевдонимТаблицыМетаданных.ЭтоГруппа
		|		И ПсевдонимТаблицыМетаданных.ПометкаУдаления
		|			ТОГДА 1
		|		КОГДА НЕ ПсевдонимТаблицыМетаданных.ЭтоГруппа
		|		И НЕ ПсевдонимТаблицыМетаданных.ПометкаУдаления
		|			ТОГДА 2
		|		КОГДА НЕ ПсевдонимТаблицыМетаданных.ЭтоГруппа
		|		И ПсевдонимТаблицыМетаданных.ПометкаУдаления
		|			ТОГДА 3
		|	КОНЕЦ КАК ИндексКартинки
		|ИЗ
		|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных
		|УПОРЯДОЧИТЬ ПО
		|	ПсевдонимТаблицыМетаданных.ЭтоГруппа ИЕРАРХИЯ,
		|	ПсевдонимТаблицыМетаданных.Наименование";
	
	ТекстЗапроса = СтрЗаменить(ШаблонТекстаЗапроса, "&ИмяТаблицыМетаданных", ПолноеИмяТаблицы);
	
	Запрос = Новый Запрос(ТекстЗапроса);		
	Возврат РезультатЗапросаВXMLДерево(Запрос);
	
КонецФункции

Функция ЭлементыИерархическогоСправочникаИерархияЭлементов(Знач ПолноеИмяТаблицы)
	
	ШаблонТекстаЗапроса =
	"ВЫБРАТЬ ПЕРВЫЕ 2000
	|	ПсевдонимТаблицыМетаданных.Ссылка,
	|	ПсевдонимТаблицыМетаданных.Представление,
	|	ВЫБОР
	|		КОГДА ПсевдонимТаблицыМетаданных.ПометкаУдаления
	|			ТОГДА 3
	|		ИНАЧЕ 2
	|	КОНЕЦ КАК ИндексКартинки
	|ИЗ
	|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных
	|УПОРЯДОЧИТЬ ПО
	|	ПсевдонимТаблицыМетаданных.Наименование ИЕРАРХИЯ";
	
	ТекстЗапроса = СтрЗаменить(ШаблонТекстаЗапроса, "&ИмяТаблицыМетаданных", ПолноеИмяТаблицы);
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Возврат РезультатЗапросаВXMLДерево(Запрос);
	
КонецФункции

Функция ЭлементыНеиерархическогоСправочника(Знач ПолноеИмяТаблицы)
	
	ШаблонТекстаЗапроса = 
	"ВЫБРАТЬ ПЕРВЫЕ 2000
	|	ПсевдонимТаблицыМетаданных.Ссылка КАК Ссылка,
	|	ПсевдонимТаблицыМетаданных.Представление КАК Представление,
	|	ВЫБОР
	|		КОГДА ПсевдонимТаблицыМетаданных.ПометкаУдаления
	|			ТОГДА 3
	|		ИНАЧЕ 2
	|	КОНЕЦ КАК ИндексКартинки
	|ИЗ
	|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных
	|
	|УПОРЯДОЧИТЬ ПО
	|	ПсевдонимТаблицыМетаданных.Наименование";
	
	ТекстЗапроса = СтрЗаменить(ШаблонТекстаЗапроса, "&ИмяТаблицыМетаданных", ПолноеИмяТаблицы);
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Возврат РезультатЗапросаВXMLДерево(Запрос);
	
КонецФункции

// Параметры:
//   Запрос - Запрос - запрос для построения дерева.
// 
// Возвращаемое значение:
//   ДеревоЗначений:
//     * Ссылка - ЛюбаяСсылка - ссылка на объект.
//     * Представление - Строка - представление объекта.
//     * ИндексКартинки - Число - индекс пиктограммы объекта.
//
Функция ДеревоЭлементов(Знач Запрос)
	
	Возврат Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
	
КонецФункции

Функция РезультатЗапросаВXMLДерево(Знач Запрос)
	
	Результат = ДеревоЭлементов(Запрос);
	Результат.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
	
	ЗаполнитьИдентификаторыСсылокВДереве(Результат.Строки);
	
	КолонкаСсылка = Результат.Колонки.Найти("Ссылка");
	Если Не КолонкаСсылка = Неопределено Тогда
		Результат.Колонки.Удалить(КолонкаСсылка);
	КонецЕсли;
	
	Возврат ОбщегоНазначения.ЗначениеВСтрокуXML(Результат);
	
КонецФункции

// Параметры:
//   СтрокиДерева - КоллекцияСтрокДереваЗначений - строки дерева идентификаторов объектов.
//
Процедура ЗаполнитьИдентификаторыСсылокВДереве(СтрокиДерева)
	
	Для Каждого Строка Из СтрокиДерева Цикл
		Строка.Идентификатор = ЗначениеВСтрокуВнутр(Строка.Ссылка);
		ЗаполнитьИдентификаторыСсылокВДереве(Строка.Строки);
	КонецЦикла;
	
КонецПроцедуры

Функция ДанныеКорреспондента(Знач ПолноеИмяТаблицы) Экспорт
	
	Результат = Новый Структура("СвойстваОбъектаМетаданных, ТаблицаБазыКорреспондента");
	
	Результат.СвойстваОбъектаМетаданных = СвойстваОбъектаМетаданных(ПолноеИмяТаблицы);
	Результат.ТаблицаБазыКорреспондента = ПолучитьОбъектыТаблицы(ПолноеИмяТаблицы);
	
	Возврат Результат;
КонецФункции

Функция ИнформацияСтатистики(ИнформацияСтатистики, Знач ВключатьУдалениеОбъектов = Ложь) Экспорт
	
	ОтборМассив = ИнформацияСтатистики.ВыгрузитьКолонку("ИмяТаблицыПриемника");
	
	ОтборСтрока = СтрСоединить(ОтборМассив, ",");
	
	Отбор = Новый Структура("ПолноеИмя", ОтборСтрока);
	
	// Получаем дерево объектов метаданных конфигурации.
	ДеревоИнформацииСтатистики = ОбменДаннымиПовтИсп.МетаданныеКонфигурации(Отбор).Скопировать(); //ДеревоЗначений
	
	// Добавляем колонки
	ДеревоИнформацииСтатистики.Колонки.Добавить("Ключ");
	ДеревоИнформацииСтатистики.Колонки.Добавить("КоличествоОбъектовВИсточнике");
	ДеревоИнформацииСтатистики.Колонки.Добавить("КоличествоОбъектовВПриемнике");
	ДеревоИнформацииСтатистики.Колонки.Добавить("КоличествоОбъектовНесопоставленных");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ПроцентСопоставленияОбъектов");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ИндексКартинки");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ИспользоватьПредварительныйПросмотр");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ИмяТаблицыПриемника");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ТипОбъектаСтрокой");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ПоляТаблицы");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ПоляПоиска");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ТипИсточникаСтрокой");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ТипПриемникаСтрокой");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ЭтоУдалениеОбъекта");
	ДеревоИнформацииСтатистики.Колонки.Добавить("ДанныеУспешноЗагружены");
	
	
	// Индексы для поиска в статистике.
	Индексы = ИнформацияСтатистики.Индексы;
	Если Индексы.Количество() = 0 Тогда
		Если ВключатьУдалениеОбъектов Тогда
			Индексы.Добавить("ЭтоУдалениеОбъекта");
			Индексы.Добавить("ОдинКоМногим, ЭтоУдалениеОбъекта");
			Индексы.Добавить("ЭтоКлассификатор, ЭтоУдалениеОбъекта");
		Иначе
			Индексы.Добавить("ОдинКоМногим");
			Индексы.Добавить("ЭтоКлассификатор");
		КонецЕсли;
	КонецЕсли;
	
	ОбработанныеСтроки = Новый Соответствие;
	
	// Обычные строки
	Отбор = Новый Структура("ОдинКоМногим", Ложь);
	Если Не ВключатьУдалениеОбъектов Тогда
		Отбор.Вставить("ЭтоУдалениеОбъекта", Ложь);
	КонецЕсли;
		
	Для Каждого СтрокаТаблицы Из ИнформацияСтатистики.НайтиСтроки(Отбор) Цикл
		СтрокаДерева = ДеревоИнформацииСтатистики.Строки.Найти(СтрокаТаблицы.ИмяТаблицыПриемника, "ПолноеИмя", Истина);
		ЗаполнитьЗначенияСвойств(СтрокаДерева, СтрокаТаблицы);
		
		СтрокаДерева.Синоним = СинонимДанныхСтрокиДереваСтатистики(СтрокаДерева, СтрокаТаблицы.ТипИсточникаСтрокой);
		
		ОбработанныеСтроки[СтрокаТаблицы] = Истина;
	КонецЦикла;
	
	// Добавляем строки с типом ОдинКоМногим.
	Отбор = Новый Структура("ОдинКоМногим", Истина);
	Если Не ВключатьУдалениеОбъектов Тогда
		Отбор.Вставить("ЭтоУдалениеОбъекта", Ложь);
	КонецЕсли;
	ЗаполнитьДеревоИнформацииСтатистикиОдинКоМногим(ДеревоИнформацииСтатистики, ИнформацияСтатистики, Отбор, ОбработанныеСтроки);
	
	// Добавляем строки классификаторов.
	Отбор = Новый Структура("ЭтоКлассификатор", Истина);
	Если Не ВключатьУдалениеОбъектов Тогда
		Отбор.Вставить("ЭтоУдалениеОбъекта", Ложь);
	КонецЕсли;
	ЗаполнитьДеревоИнформацииСтатистикиОдинКоМногим(ДеревоИнформацииСтатистики, ИнформацияСтатистики, Отбор, ОбработанныеСтроки);
	
	// Добавляем строки удаления объектов.
	Если ВключатьУдалениеОбъектов Тогда
		Отбор = Новый Структура("ЭтоУдалениеОбъекта", Истина);
		ЗаполнитьДеревоИнформацииСтатистикиОдинКоМногим(ДеревоИнформацииСтатистики, ИнформацияСтатистики, Отбор, ОбработанныеСтроки);
	КонецЕсли;
	
	// Очищаем пустые строки
	СтрокиСтатистики = ДеревоИнформацииСтатистики.Строки;
	ПозицияГруппы = СтрокиСтатистики.Количество() - 1;
	Пока ПозицияГруппы >=0 Цикл
		Группа = СтрокиСтатистики[ПозицияГруппы];
		
		Элементы = Группа.Строки;
		Позиция = Элементы.Количество() - 1;
		Пока Позиция >=0 Цикл
			Элемент = Элементы[Позиция];
			
			Если Элемент.КоличествоОбъектовВПриемнике = Неопределено 
				И Элемент.КоличествоОбъектовВИсточнике = Неопределено
				И Элемент.Строки.Количество() = 0 Тогда
				Элементы.Удалить(Элемент);
			КонецЕсли;
			
			Позиция = Позиция - 1;
		КонецЦикла;
		
		Если Элементы.Количество() = 0 Тогда
			СтрокиСтатистики.Удалить(Группа);
		КонецЕсли;
		ПозицияГруппы = ПозицияГруппы - 1;
	КонецЦикла;
	
	Возврат ДеревоИнформацииСтатистики;
КонецФункции

// Параметры:
//   ДеревоИнформацииСтатистики - ДеревоЗначений
//   ИнформацияСтатистики - ТаблицаЗначений
//   Отбор - Структура
//   УжеОбработанныеСтроки - Соответствие
//
Процедура ЗаполнитьДеревоИнформацииСтатистикиОдинКоМногим(ДеревоИнформацииСтатистики, ИнформацияСтатистики, Отбор, УжеОбработанныеСтроки)
	
	СтрокиДляОбработки = ИнформацияСтатистики.НайтиСтроки(Отбор);
	
	// Игнорируем уже обработанные строки источника.
	Позиция = СтрокиДляОбработки.ВГраница();
	Пока Позиция >= 0 Цикл
		Кандидат = СтрокиДляОбработки[Позиция];
		
		Если УжеОбработанныеСтроки[Кандидат] <> Неопределено Тогда
			СтрокиДляОбработки.Удалить(Позиция);
		Иначе
			УжеОбработанныеСтроки[Кандидат] = Истина;
		КонецЕсли;
		
		Позиция = Позиция - 1;
	КонецЦикла;
		
	Если СтрокиДляОбработки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ИнформацияСтатистикиОдинКоМногим = ИнформацияСтатистики.Скопировать(СтрокиДляОбработки);
	ИнформацияСтатистикиОдинКоМногим.Индексы.Добавить("ИмяТаблицыПриемника");
	
	ИнформацияСтатистикиОдинКоМногимВременная = ИнформацияСтатистикиОдинКоМногим.Скопировать(СтрокиДляОбработки, "ИмяТаблицыПриемника");
	
	ИнформацияСтатистикиОдинКоМногимВременная.Свернуть("ИмяТаблицыПриемника");
	
	Для Каждого СтрокаТаблицы Из ИнформацияСтатистикиОдинКоМногимВременная Цикл
		Строки       = ИнформацияСтатистикиОдинКоМногим.НайтиСтроки(Новый Структура("ИмяТаблицыПриемника", СтрокаТаблицы.ИмяТаблицыПриемника));
		СтрокаДерева = ДеревоИнформацииСтатистики.Строки.Найти(СтрокаТаблицы.ИмяТаблицыПриемника, "ПолноеИмя", Истина);
		
		Для Каждого Строка Из Строки Цикл
			НоваяСтрокаДерева = СтрокаДерева.Строки.Добавить();
			ЗаполнитьЗначенияСвойств(НоваяСтрокаДерева, СтрокаДерева);
			ЗаполнитьЗначенияСвойств(НоваяСтрокаДерева, Строка);
			
			Если Строка.ЭтоУдалениеОбъекта Тогда
				НоваяСтрокаДерева.Картинка = БиблиотекаКартинок.ПометитьНаУдаление;
			Иначе
				НоваяСтрокаДерева.Синоним = СинонимДанныхСтрокиДереваСтатистики(НоваяСтрокаДерева, Строка.ТипИсточникаСтрокой) ;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

Функция УдалитьИмяКлассаИзИмениОбъекта(Знач Результат)
	
	Результат = СтрЗаменить(Результат, "ДокументСсылка.", "");
	Результат = СтрЗаменить(Результат, "СправочникСсылка.", "");
	Результат = СтрЗаменить(Результат, "ПланВидовХарактеристикСсылка.", "");
	Результат = СтрЗаменить(Результат, "ПланСчетовСсылка.", "");
	Результат = СтрЗаменить(Результат, "ПланВидовРасчетаСсылка.", "");
	Результат = СтрЗаменить(Результат, "БизнесПроцессСсылка.", "");
	Результат = СтрЗаменить(Результат, "ЗадачаСсылка.", "");
	
	Возврат Результат;
КонецФункции

Процедура ВыполнитьПроверкуНаличияПравилОбменаЗагруженныхИзФайла(ПравилаОбменаЗагруженныеИзФайла, ПравилаРегистрацииЗагруженныеИзФайла)
	
	ТекстЗапроса = 
		"ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ПравилаДляОбменаДанными.ИмяПланаОбмена КАК ИмяПланаОбмена,
		|	ПравилаДляОбменаДанными.ВидПравил КАК ВидПравил
		|ИЗ
		|	РегистрСведений.ПравилаДляОбменаДанными КАК ПравилаДляОбменаДанными
		|ГДЕ
		|	(ПравилаДляОбменаДанными.ИсточникПравил = ЗНАЧЕНИЕ(Перечисление.ИсточникиПравилДляОбменаДанными.Файл)
		|			ИЛИ ПравилаДляОбменаДанными.ИсточникПравил = ЗНАЧЕНИЕ(Перечисление.ИсточникиПравилДляОбменаДанными.МенеджерПользовательский))
		|	И ПравилаДляОбменаДанными.ПравилаЗагружены";
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	
	Результат = Запрос.Выполнить();
	
	Если Не Результат.Пустой() Тогда
		
		ПланыОбменаМассив = Новый Массив;
		
		Выборка = Результат.Выбрать();
		
		Пока Выборка.Следующий() Цикл
			
			Если Выборка.ВидПравил = Перечисления.ВидыПравилДляОбменаДанными.ПравилаКонвертацииОбъектов Тогда
				
				ПравилаОбменаЗагруженныеИзФайла.Добавить(Выборка.ИмяПланаОбмена);
				
			ИначеЕсли Выборка.ВидПравил = Перечисления.ВидыПравилДляОбменаДанными.ПравилаРегистрацииОбъектов Тогда
				
				ПравилаРегистрацииЗагруженныеИзФайла.Добавить(Выборка.ИмяПланаОбмена);
				
			КонецЕсли;
			
			Если ПланыОбменаМассив.Найти(Выборка.ИмяПланаОбмена) = Неопределено Тогда
				
				ПланыОбменаМассив.Добавить(Выборка.ИмяПланаОбмена);
				
			КонецЕсли;
			
		КонецЦикла;
		
		СтрокаСообщения = НСтр("ru = 'Для планов обмена %1 используются правила обмена, загруженные из файла.
				|Эти правила могут быть несовместимы с новой версией программы.
				|Для предупреждения возможного возникновения ошибок при работе с программой рекомендуется актуализировать правила обмена из файла.'",
				ОбщегоНазначения.КодОсновногоЯзыка());
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, СтрСоединить(ПланыОбменаМассив, ","));
		
		ЗаписьЖурналаРегистрации(ОбновлениеИнформационнойБазы.СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка,,, СтрокаСообщения);
		
	КонецЕсли;
	
КонецПроцедуры

// Основная функция для использования внешнего соединения при обмене.
//
// Параметры: 
//  СтруктураНастроек - структура настроек транспорта COM обмена.
//
// Возвращаемое значение:
//  Структура:
//    * Соединение                  - COMОбъект
//                                  - Неопределено - указатель на COM-объект соединения или Неопределено в
//                                    случае ошибки;
//    * КраткоеОписаниеОшибки       - Строка - краткое описание ошибки;
//    * ПодробноеОписаниеОшибки     - Строка - подробное описание ошибки;
//    * ОшибкаПодключенияКомпоненты - Булево - флаг ошибки подключения COM.
//
Функция УстановитьВнешнееСоединениеСБазой(СтруктураНастроек) Экспорт
	
	Результат = ОбщегоНазначения.УстановитьВнешнееСоединениеСБазой(
		ЗаполнитьПараметрыПодключенияВнешнегоСоединения(СтруктураНастроек));
	
	ВнешнееСоединение = Результат.Соединение;
	Если ВнешнееСоединение = Неопределено Тогда
		// Ошибка установки соединения.
		Возврат Результат;
	КонецЕсли;
	
	// Для конфигураций с разными вариантами встроенного языка COM соединение не работает
	
	ВариантВстроенногоЯзыкаКорреспондента = "";
	ВариантыВстроенногоЯзыкаОтличаются = Ложь;
	Если Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский
		И ВнешнееСоединение.Метаданные.ВариантВстроенногоЯзыка <> ВнешнееСоединение.Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский Тогда
		ВариантВстроенногоЯзыкаКорреспондента = НСтр("ru = 'Английский'");
		ВариантыВстроенногоЯзыкаОтличаются = Истина;
	КонецЕсли;
	
	Если Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Английский
		И ВнешнееСоединение.Метаданные.ВариантВстроенногоЯзыка <> ВнешнееСоединение.Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Английский Тогда
		ВариантВстроенногоЯзыкаКорреспондента = НСтр("ru = 'Русский'");
		ВариантыВстроенногоЯзыкаОтличаются = Истина;
	КонецЕсли;
	
	Если ВариантыВстроенногоЯзыкаОтличаются Тогда
		
		ПодробноеОписаниеОшибки = НСтр("ru = 'В подключаемой программе отличается вариант встроенного языка (%1). Подключение невозможно.'");
		ПодробноеОписаниеОшибки = СтрШаблон(ПодробноеОписаниеОшибки, ВариантВстроенногоЯзыкаКорреспондента); 
		
		Результат.ПодробноеОписаниеОшибки = ПодробноеОписаниеОшибки;
		Результат.КраткоеОписаниеОшибки   = ПодробноеОписаниеОшибки;
		Результат.Соединение = Неопределено;
		
		Возврат Результат;
		
	КонецЕсли;
		
	// Дополнительно проверяем возможность работы с внешней базой.
	
	Попытка
		НетПолныхПрав = Не ВнешнееСоединение.ОбменДаннымиВнешнееСоединение.РольДоступнаПолныеПрава();
	Исключение
		НетПолныхПрав = Истина;
	КонецПопытки;
	
	Если НетПолныхПрав Тогда
		Результат.ПодробноеОписаниеОшибки = НСтр("ru = 'Пользователю, указанному для подключения к другой программе, должны быть назначены роли ""Администратор системы"" и ""Полные права""'");
		Результат.КраткоеОписаниеОшибки   = Результат.ПодробноеОписаниеОшибки;
		Результат.Соединение = Неопределено;
	Иначе
		Попытка 
			СостояниеНеДопустимо = ВнешнееСоединение.ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы();
		Исключение
			СостояниеНеДопустимо = Ложь
		КонецПопытки;
		
		Если СостояниеНеДопустимо Тогда
			Результат.ПодробноеОписаниеОшибки = НСтр("ru = 'Другая программа находится в состоянии обновления.'");
			Результат.КраткоеОписаниеОшибки   = Результат.ПодробноеОписаниеОшибки;
			Результат.Соединение = Неопределено;
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция НастройкиТранспортаПоПараметрамВнешнегоСоединения(Параметры)
	
	// Преобразуем настройки - параметры внешнего соединения в параметры транспорта.
	НастройкиТранспорта = Новый Структура;
	
	НастройкиТранспорта.Вставить("COMПарольПользователя",
		ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ПарольПользователя"));
	НастройкиТранспорта.Вставить("COMИмяПользователя",
		ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ИмяПользователя"));
	НастройкиТранспорта.Вставить("COMАутентификацияОперационнойСистемы",
		ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "АутентификацияОперационнойСистемы"));
	НастройкиТранспорта.Вставить("COMИмяИнформационнойБазыНаСервере1СПредприятия",
		ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ИмяИнформационнойБазыНаСервере1СПредприятия"));
	НастройкиТранспорта.Вставить("COMИмяСервера1СПредприятия",
		ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ИмяСервера1СПредприятия"));
	НастройкиТранспорта.Вставить("COMКаталогИнформационнойБазы",
		ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "КаталогИнформационнойБазы"));
	НастройкиТранспорта.Вставить("COMВариантРаботыИнформационнойБазы",
		ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ВариантРаботыИнформационнойБазы"));
	
	Возврат НастройкиТранспорта;
	
КонецФункции

Процедура УдалитьНезначащиеСимволыВНастройкахПодключения(Настройки) Экспорт
	
	Для Каждого Настройка Из Настройки Цикл
		
		Если ТипЗнч(Настройка.Значение) = Тип("Строка") Тогда
			
			Настройки.Вставить(Настройка.Ключ, СокрЛП(Настройка.Значение));
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Выводит сообщение об ошибке и выставляет параметр Отказ в "Истина".
//
// Параметры:
//  ТекстСообщения - Строка - текст сообщения.
//  Отказ          - Булево - признак отказа
//
Процедура СообщитьОбОшибке(ТекстСообщения, Отказ = Ложь) Экспорт
	
	Отказ = Истина;
	
	ОбщегоНазначения.СообщитьПользователю(ТекстСообщения);
	
КонецПроцедуры

// Выполняет загрузку правил для обмена данными (ПРО или ПКО) в ИБ.
// 
Процедура ЗагрузитьПравилаДляОбменаДанными(Отказ,
										Знач ИмяПланаОбмена,
										Знач ВидПравил,
										Знач ИмяМакетаПравил,
										Знач ИмяМакетаПравилКорреспондента = "")
	
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("ИмяПланаОбмена",  ИмяПланаОбмена);
	СтруктураЗаписи.Вставить("ВидПравил",       ВидПравил);
	
	Если Не ПустаяСтрока(ИмяМакетаПравилКорреспондента) Тогда
	
		СтруктураЗаписи.Вставить("ИмяМакетаПравилКорреспондента", ИмяМакетаПравилКорреспондента);
		
	КонецЕсли;
	
	СтруктураЗаписи.Вставить("ИмяМакетаПравил", ИмяМакетаПравил);
	СтруктураЗаписи.Вставить("ИсточникПравил",  Перечисления.ИсточникиПравилДляОбменаДанными.МакетКонфигурации);
	
	Если ВидПравил = Перечисления.ВидыПравилДляОбменаДанными.ПравилаРегистрацииОбъектов Тогда
		
		ПараметрыВыборочнойРегистрации = ОбменДаннымиРегистрацияСервер.НовыеПараметрыВыборочнойРегистрацииДанныхПланаОбмена(ИмяПланаОбмена);
		СтруктураЗаписи.Вставить("ПараметрыВыборочнойРегистрации", Новый ХранилищеЗначения(ПараметрыВыборочнойРегистрации));
		
	КонецЕсли;
	
	// Получаем набор записей регистра.
	НаборЗаписей = ОбменДаннымиСлужебный.СоздатьНаборЗаписейРегистраСведений(СтруктураЗаписи, "ПравилаДляОбменаДанными");
	
	// Добавляем только одну запись в новый набор записей.
	НоваяЗапись = НаборЗаписей.Добавить();
	
	// Заполняем значения свойств записи из структуры.
	ЗаполнитьЗначенияСвойств(НоваяЗапись, СтруктураЗаписи);
	
	// Загружаем правила для обмена данными в ИБ.
	РегистрыСведений.ПравилаДляОбменаДанными.ЗагрузитьПравила(Отказ, НаборЗаписей[0]);
	
	Если Не Отказ Тогда
		
		НаборЗаписей.Записать();
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗагрузитьМенеджерРегистрацииОбменаДанными(Отказ, Знач ИмяПланаОбмена)
	
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("ИмяПланаОбмена",  ИмяПланаОбмена);
	СтруктураЗаписи.Вставить("ВидПравил",       Перечисления.ВидыПравилДляОбменаДанными.ПравилаРегистрацииОбъектов);
	СтруктураЗаписи.Вставить("ИсточникПравил",  Перечисления.ИсточникиПравилДляОбменаДанными.МенеджерТиповой);
	
	ПараметрыВыборочнойРегистрации = ОбменДаннымиРегистрацияСервер.НовыеПараметрыВыборочнойРегистрацииДанныхПланаОбмена(ИмяПланаОбмена);
	СтруктураЗаписи.Вставить("ПараметрыВыборочнойРегистрации", Новый ХранилищеЗначения(ПараметрыВыборочнойРегистрации));
	
	ИмяМенеджераРегистрации = ОбменДаннымиПовтИсп.ИмяМенеджераРегистрации(ИмяПланаОбмена);
	СтруктураЗаписи.Вставить("ИмяМенеджераРегистрации", ИмяМенеджераРегистрации);
	
	Менеджер = ОбщегоНазначения.ОбщийМодуль(ИмяМенеджераРегистрации);
	СтруктураЗаписи.Вставить("ИнформацияОПравилах", Менеджер.ИнформацияОПравилах());
	
	// Получаем набор записей регистра.
	НаборЗаписей = ОбменДаннымиСлужебный.СоздатьНаборЗаписейРегистраСведений(СтруктураЗаписи, "ПравилаДляОбменаДанными");
	
	// Добавляем только одну запись в новый набор записей.
	НоваяЗапись = НаборЗаписей.Добавить();
	
	// Заполняем значения свойств записи из структуры.
	ЗаполнитьЗначенияСвойств(НоваяЗапись, СтруктураЗаписи);
		
	Если Не Отказ Тогда
		
		НаборЗаписей.Записать();
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьОбновлениеВерсииТиповыхПравилДляОбменаДанными(ПравилаОбменаЗагруженныеИзФайла, ПравилаРегистрацииЗагруженныеИзФайла)
	
	Отказ = Ложь;
	
	ШаблонТекстаЗапроса =
	"ВЫБРАТЬ
	|	КОЛИЧЕСТВО(ПсевдонимТаблицыМетаданных.Ссылка) КАК Количество,
	|	""&ИмяПланаОбмена"" КАК ИмяПланаОбмена
	|ИЗ
	|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных";
	
	ТекстЗапроса = "";
	Для Каждого ИмяПланаОбмена Из ОбменДаннымиПовтИсп.ПланыОбменаБСП() Цикл
		
		Если Не ПустаяСтрока(ТекстЗапроса) Тогда
			
			ТекстЗапроса = ТекстЗапроса + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС;
			
		КонецЕсли;
		
		ТекстПодзапроса = СтрЗаменить(ШаблонТекстаЗапроса, "&ИмяТаблицыМетаданных", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("ПланОбмена.%1", ИмяПланаОбмена));
		ТекстПодзапроса = СтрЗаменить(ТекстПодзапроса, "&ИмяПланаОбмена", ИмяПланаОбмена);
		ТекстЗапроса = ТекстЗапроса + ТекстПодзапроса;
		
	КонецЦикла;
	
	Если ПустаяСтрока(ТекстЗапроса) Тогда
		
		Возврат;
		
	КонецЕсли;
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Результат = Запрос.Выполнить().Выгрузить();
	
	ВыполненоОбновлениеПравил = Ложь;
	Для Каждого ЗаписьПланаОбмена Из Результат Цикл
		
		Если ЗаписьПланаОбмена.Количество <= 1 
			И Не ОбщегоНазначения.РазделениеВключено() Тогда // только ЭтотУзел
			Продолжить;
		КонецЕсли;
		
		ИмяПланаОбмена = ЗаписьПланаОбмена.ИмяПланаОбмена;
		
		Если ОбменДаннымиПовтИсп.ЕстьМакетПланаОбмена(ИмяПланаОбмена, "ПравилаОбмена")
			И ОбменДаннымиПовтИсп.ЕстьМакетПланаОбмена(ИмяПланаОбмена, "ПравилаОбменаКорреспондента") Тогда
			
			Если ПравилаОбменаЗагруженныеИзФайла.Найти(ИмяПланаОбмена) = Неопределено Тогда
			
				ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Выполняется обновление правил конвертации данных для плана обмена %1'"), ИмяПланаОбмена);
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(),
					УровеньЖурналаРегистрации.Информация,,, ТекстСообщения);
				
				ЗагрузитьПравилаДляОбменаДанными(Отказ, ИмяПланаОбмена, Перечисления.ВидыПравилДляОбменаДанными.ПравилаКонвертацииОбъектов,
					"ПравилаОбмена", "ПравилаОбменаКорреспондента");
					
				Если Не Отказ Тогда
					ВыполненоОбновлениеПравил = Истина;
					СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы(
						"СтандартныеПодсистемы.ОбменДанными.ПравилаКонвертации." + ИмяПланаОбмена, Истина);
				КонецЕсли;
				
			Иначе
				
				СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы(
					"СтандартныеПодсистемы.ОбменДанными.ПравилаКонвертации." + ИмяПланаОбмена, Ложь);
				
			КонецЕсли;
			
		КонецЕсли;
		
		Если ПравилаРегистрацииЗагруженныеИзФайла.Найти(ИмяПланаОбмена) <> Неопределено Тогда
				
			СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы(
				"СтандартныеПодсистемы.ОбменДанными.ПравилаРегистрации." + ИмяПланаОбмена, Ложь);
			
		ИначеЕсли Не ОбменДаннымиПовтИсп.ЕстьМакетПланаОбмена(ИмяПланаОбмена, "ПравилаРегистрации")
			И Не ОбменДаннымиПовтИсп.ПравилаРегистрацииВМенеджере(ИмяПланаОбмена) Тогда
			
			СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы(
				"СтандартныеПодсистемы.ОбменДанными.ПравилаРегистрации." + ИмяПланаОбмена, Ложь);
			
		Иначе
			
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Выполняется обновление правил регистрации данных для плана обмена %1'"), ИмяПланаОбмена);
				
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииОбменДанными(),
				УровеньЖурналаРегистрации.Информация,,, ТекстСообщения);
					
			Если ОбменДаннымиПовтИсп.ПравилаРегистрацииВМенеджере(ИмяПланаОбмена) Тогда
				ЗагрузитьМенеджерРегистрацииОбменаДанными(Отказ, ИмяПланаОбмена);
			Иначе
				ЗагрузитьПравилаДляОбменаДанными(Отказ, ИмяПланаОбмена, 
					Перечисления.ВидыПравилДляОбменаДанными.ПравилаРегистрацииОбъектов, "ПравилаРегистрации");
			КонецЕсли;
			
			Если Не Отказ Тогда
				ВыполненоОбновлениеПравил = Истина;
				СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы(
					"СтандартныеПодсистемы.ОбменДанными.ПравилаРегистрации." + ИмяПланаОбмена, Истина);
			КонецЕсли;

		КонецЕсли
		
	КонецЦикла;
	
	Если Отказ Тогда
		ВызватьИсключение НСтр("ru = 'При обновлении правил обмена данными возникли ошибки (см. Журнал регистрации).'");
	КонецЕсли;
	
	Если ВыполненоОбновлениеПравил Тогда
		ОбменДаннымиСлужебный.СброситьКэшМеханизмаРегистрацииОбъектов();
	КонецЕсли;
	
КонецПроцедуры

// Получает индекс картинки для вывода в таблице статистики сопоставления объектов.
//
Функция ИндексКартинкиТаблицыИнформацииСтатистики(Знач КоличествоОбъектовНесопоставленных, Знач ДанныеУспешноЗагружены) Экспорт
	
	Возврат ?(КоличествоОбъектовНесопоставленных = 0, ?(ДанныеУспешноЗагружены = Истина, 2, 0), 1);
	
КонецФункции

// Выполняет проверку того, что размер файла сообщения обмена превышает допустимый размер.
//
//  Возвращаемое значение:
//   Истина - если размер файла больше допустимого, иначе Ложь.
//
Функция РазмерСообщенияОбменаПревышаетДопустимый(Знач ИмяФайла, Знач МаксимальныйДопустимыйРазмерСообщения) Экспорт
	
	// Возвращаемое значение функции.
	Результат = Ложь;
	
	Файл = Новый Файл(ИмяФайла);
	
	Если Файл.Существует() И Файл.ЭтоФайл() Тогда
		
		Если МаксимальныйДопустимыйРазмерСообщения <> 0 Тогда
			
			РазмерПакета = Окр(Файл.Размер() / 1024, 0, РежимОкругления.Окр15как20);
			
			Если РазмерПакета > МаксимальныйДопустимыйРазмерСообщения Тогда
				
				СтрокаСообщения = НСтр("ru = 'Размер исходящего пакета составил %1 Кбайт, что превышает допустимое ограничение %2 Кбайт.'");
				СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, Строка(РазмерПакета), Строка(МаксимальныйДопустимыйРазмерСообщения));
				СообщитьОбОшибке(СтрокаСообщения, Результат);
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция УстановленПризнакНачальнойВыгрузкиДанных(УзелИнформационнойБазы) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.УстановленПризнакНачальнойВыгрузкиДанных(УзелИнформационнойБазы);
	
КонецФункции

// Выполняет загрузку сообщения обмена, которое содержало
// изменения конфигурации, до обновления информационной базы.
//
Процедура ЗагрузитьСообщениеПередОбновлениемИнформационнойБазы()
	
	Если ОбменДаннымиСлужебный.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском(
			"ПропуститьЗагрузкуСообщенияОбменаДаннымиПередЗапуском") Тогда
		Возврат;
	КонецЕсли;
	
	Если ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюДанных") Тогда
		
		УзелИнформационнойБазы = ГлавныйУзел();
		
		Если УзелИнформационнойБазы <> Неопределено Тогда
			
			УстановитьПривилегированныйРежим(Истина);
			УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРазрешена", Истина);
			УстановитьПривилегированныйРежим(Ложь);
			
			Попытка
				// Обновление правил регистрации объектов выполняем до загрузки данных.
				ВыполнитьОбновлениеПравилДляОбменаДанными();
				
				ВидТранспорта = РегистрыСведений.НастройкиТранспортаОбменаДанными.ВидТранспортаСообщенийОбменаПоУмолчанию(УзелИнформационнойБазы);
				
				Отказ = Ложь;
				
				ПараметрыОбмена = ПараметрыОбмена();
				ПараметрыОбмена.ВидТранспортаСообщенийОбмена = ВидТранспорта;
				ПараметрыОбмена.ВыполнятьЗагрузку = Истина;
				ПараметрыОбмена.ВыполнятьВыгрузку = Ложь;
				ВыполнитьОбменДаннымиДляУзлаИнформационнойБазы(УзелИнформационнойБазы, ПараметрыОбмена, Отказ);
				
				// Режим повтора требует включения в следующих случаях.
				// Случай 1. Получены метаданные с новой версией конфигурации, т.е. будет выполнено обновление ИБ.
				// Е если Отказ = Истина, тогда недопустимо продолжение, т.к. могут быть созданы дубли генерируемых данных,
				// - если Отказ = Ложь, тогда возможна ошибка при обновлении ИБ, возможно требующая повторной загрузки сообщения.
				// Случай 2. Получены метаданные с той же версией конфигурации, т.е. не будет выполнено обновление ИБ.
				// Е если Отказ = Истина, тогда возможна ошибка при продолжении запуска, например, из-за того, что
				//   не были загружены предопределенные элементы,
				// - если Отказ = Ложь, тогда продолжение возможно, т.к. выгрузку можно сделать позднее (если же
				//   выгрузка не выполняется успешно, тогда позднее можно получить и новое сообщение для загрузки).
				
				Если Отказ ИЛИ ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы() Тогда
					ВключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском();
				КонецЕсли;
				
				Если Отказ Тогда
					ВызватьИсключение НСтр("ru = 'Получение данных из главного узла завершилось с ошибками.'");
				КонецЕсли;
			Исключение
				УстановитьПривилегированныйРежим(Истина);
				УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРазрешена", Ложь);
				УстановитьПривилегированныйРежим(Ложь);
				ВызватьИсключение;
			КонецПопытки;
			УстановитьПривилегированныйРежим(Истина);
			УстановитьРежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРазрешена", Ложь);
			УстановитьПривилегированныйРежим(Ложь);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Сбрасывает признак повторения загрузки при ошибке загрузки или обновления.
Процедура ОтключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если Константы.ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском.Получить() Тогда
		Константы.ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском.Установить(Ложь);
	КонецЕсли;
	
КонецПроцедуры

// Выполняет загрузку и выгрузку сообщения обмена, которое
// содержало изменения конфигурации, которые не потребовали
// обновления информационной базы.
//
Процедура ВыполнитьСинхронизациюПриОтсутствииОбновленияИнформационнойБазы(
		ПриЗапускеКлиентскогоПриложения, Перезапустить)
	
	Если Не ЗагрузитьСообщениеОбменаДанными() Тогда
		// Если загрузка сообщения обмена была отменена, а версия конфигурации
		// в изменениях метаданных не была повышена, тогда повторение загрузки нужно отключить.
		ОтключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском();
		Возврат;
	КонецЕсли;
		
	Если КонфигурацияИзменена() Тогда
		// Изменения конфигурации загружены, но не применены.
		// Загружать сообщение еще рано.
		Возврат;
	КонецЕсли;
	
	НачатьТранзакцию();
	Попытка
		ЗагрузитьСообщениеПередОбновлениемИнформационнойБазы();
		ЗафиксироватьТранзакцию();
	Исключение
		Если КонфигурацияИзменена() Тогда
			Если Не ОбменДаннымиСлужебный.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском(
				"СообщениеПолученоИзКэша") Тогда
				// Переход с конфигурации, в которой не использовалось кэширование
				// сообщения обмена. Возможно, новое загруженное сообщение содержит
				// новые изменения конфигурации. Определить возврат к конфигурации
				// базы данных невозможно. Следует зафиксировать транзакцию и продолжить
				// запуск без выгрузки нового сообщения обмена.
				ЗафиксироватьТранзакцию();
				Возврат;
			Иначе
				// Вновь получены изменения конфигурации, значит
				// был выполнен возврат к конфигурации базы данных.
				// Следует отменить загрузку.
				ОтменитьТранзакцию();
				УстановитьПривилегированныйРежим(Истина);
				Константы.ЗагрузитьСообщениеОбменаДанными.Установить(Ложь);
				ОчиститьСообщениеОбменаДаннымиИзГлавногоУзла();
				УстановитьПривилегированныйРежим(Ложь);
				ЗаписатьСобытиеПолученияДанных(ГлавныйУзел(),
					НСтр("ru = 'Обнаружен возврат к конфигурации базы данных.
					           |Синхронизация отменена.'"));
				Возврат;
			КонецЕсли;
		КонецЕсли;
		// Если был выполнен возврат к конфигурации базы данных,
		// но конфигуратор не был закрыт. Тогда новое сообщение не загружено.
		// Перейдя в режим повтора и в этом случае, можно будет нажать кнопку
		// "Не синхронизировать и продолжить" после чего возврат к конфигурации
		// базы данных будет закончен успешно.
		ЗафиксироватьТранзакцию();
		ВключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском();
		Если ПриЗапускеКлиентскогоПриложения Тогда
			Перезапустить = Истина;
			Возврат;
		КонецЕсли;
		ВызватьИсключение;
	КонецПопытки;
	
	ВыгрузитьСообщениеПослеОбновленияИнформационнойБазы();
	
КонецПроцедуры

Функция ЭтоПодчиненныйУзелРИБ() Экспорт
	
	Возврат ГлавныйУзел() <> Неопределено;
	
КонецФункции

// Возвращает массив номеров версий, поддерживаемых интерфейсом корреспондента для подсистемы ОбменДанными.
// 
// Параметры:
//   ВнешнееСоединение - объект COM-соединение, которое используется для работы с корреспондентом.
//
// Возвращаемое значение:
//   Массив номеров версий, поддерживаемых интерфейсом корреспондента.
//
Функция ВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение) Экспорт
	
	Возврат ОбщегоНазначения.ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, "ОбменДанными");
	
КонецФункции

// Создает временный каталог сообщений обмена.
// Фиксирует имя каталога в регистре для последующего его удаления.
//
Функция СоздатьВременныйКаталогСообщенийОбмена(ИдентификаторКаталога = Неопределено) Экспорт
	
	Результат = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременногоХранилищаФайлов(), ИмяВременногоКаталогаСообщенийОбмена());
	
	СоздатьКаталог(Результат);
	
	Если Не ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
		
		УстановитьПривилегированныйРежим(Истина);
		
		ИдентификаторКаталога = ПоместитьФайлВХранилище(Результат);
		
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция ВариантОбменаДанными(Знач Корреспондент) Экспорт
	
	Результат = "Синхронизация";
	
	Если ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(Корреспондент) Тогда
		Возврат Результат;
	КонецЕсли;
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Корреспондент);
	ИдентификаторНастройки = СохраненныйВариантНастройкиУзлаПланаОбмена(Корреспондент);
	ПоддерживаетсяСопоставлениеДанных = ЗначениеНастройкиПланаОбмена(ИмяПланаОбмена, 
		"ПоддерживаетсяСопоставлениеДанных", ИдентификаторНастройки);
	
	Если Не ПоддерживаетсяСопоставлениеДанных Тогда
		Возврат Результат;
	КонецЕсли;
	
	ИменаРеквизитов = ОбщегоНазначения.ИменаРеквизитовПоТипу(Корреспондент, Тип("ПеречислениеСсылка.РежимыВыгрузкиОбъектовОбмена"));
	
	ЗначенияРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Корреспондент, ИменаРеквизитов);
	
	Для Каждого Реквизит Из ЗначенияРеквизитов Цикл
			
		Если Реквизит.Значение = Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьВручную
			Или Реквизит.Значение = Перечисления.РежимыВыгрузкиОбъектовОбмена.НеВыгружать Тогда
			
			Результат = "ПолучениеИОтправка";
			Прервать;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//   Контекст - Структура - структура со значениями для переноса в объект.
//   Объект - ОбработкаОбъект.СопоставлениеОбъектовИнформационныхБаз - объект-приемник данных.
// 
Процедура ЗагрузитьКонтекстОбъекта(Знач Контекст, Знач Объект) Экспорт
	
	Для Каждого Реквизит Из Объект.Метаданные().Реквизиты Цикл
		
		Если Контекст.Свойство(Реквизит.Имя) Тогда
			
			Объект[Реквизит.Имя] = Контекст[Реквизит.Имя];
			
		КонецЕсли;
		
	КонецЦикла;
	
	Для Каждого ТабличнаяЧасть Из Объект.Метаданные().ТабличныеЧасти Цикл
		
		Если Контекст.Свойство(ТабличнаяЧасть.Имя) Тогда
			
			Объект[ТабличнаяЧасть.Имя].Загрузить(Контекст[ТабличнаяЧасть.Имя]);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Для внутреннего использования.
//
// Параметры:
//   Объект - СправочникОбъект, ДокументОбъект и т.п. - объект данных.
// 
// Возвращаемое значение:
//   Структура - объект данных в виде структуры. Ключи соответствуют именам реквизитов и табличных частей,
//               значения - соответствующим им значениям.
//
Функция ПолучитьКонтекстОбъекта(Знач Объект) Экспорт
	
	Результат = Новый Структура;
	
	МетаданныеОбъекта = Объект.Метаданные(); // ОбъектМетаданных
	
	Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
		
		Результат.Вставить(Реквизит.Имя, Объект[Реквизит.Имя]);
		
	КонецЦикла;
	
	Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.ТабличныеЧасти Цикл
		
		Результат.Вставить(ТабличнаяЧасть.Имя, Объект[ТабличнаяЧасть.Имя].Выгрузить());
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Параметры:
//   Таблица - ТаблицаЗначений - объект-приемник данных.
//   Дерево - КоллекцияСтрокДереваЗначений - объект-источник данных.
//
Процедура РазвернутьДеревоЗначений(Таблица, Дерево)
	
	Для Каждого СтрокаДерева Из Дерево Цикл
		
		ЗаполнитьЗначенияСвойств(Таблица.Добавить(), СтрокаДерева);
		
		Если СтрокаДерева.Строки.Количество() > 0 Тогда
			
			РазвернутьДеревоЗначений(Таблица, СтрокаДерева.Строки);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция КоличествоДнейРазницы(Знач Дата1, Знач Дата2)
	
	Возврат Цел((НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400);
	
КонецФункции

// Параметры:
//   ТаблицаЗначений - ТаблицаЗначений - таблица значений для преобразования
//
Функция ТаблицаВМассивСтруктур(Знач ТаблицаЗначений)
	Результат = Новый Массив;
	
	ИменаКолонок = "";
	Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
		ИменаКолонок = ИменаКолонок + "," + Колонка.Имя;
	КонецЦикла;
	ИменаКолонок = Сред(ИменаКолонок, 2);
	
	Для Каждого Строка Из ТаблицаЗначений Цикл
		СтруктураСтроки = Новый Структура(ИменаКолонок);
		ЗаполнитьЗначенияСвойств(СтруктураСтроки, Строка);
		Результат.Добавить(СтруктураСтроки);
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Проверка на различие версии корреспондента в правилах текущей и другой программы.
//
Функция РазличаютсяВерсииКорреспондента(ИмяПланаОбмена, КлючСообщенияЖурналаРегистрации, ВерсияВЭтойПрограмме,
	ВерсияВДругойПрограмме, ТекстСообщения, ПараметрыВнешнегоСоединения = Неопределено) Экспорт
	
	ВерсияВЭтойПрограмме = ?(ЗначениеЗаполнено(ВерсияВЭтойПрограмме), ВерсияВЭтойПрограмме, ВерсияКорреспондентаВПравилах(ИмяПланаОбмена));
	
	Если ЗначениеЗаполнено(ВерсияВЭтойПрограмме) И ЗначениеЗаполнено(ВерсияВДругойПрограмме)
		И ЗначениеНастройкиПланаОбмена(ИмяПланаОбмена, "ПредупреждатьОНесоответствииВерсийПравилОбмена") Тогда
		
		ВерсияВЭтойПрограммеБезНомераСборки = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(ВерсияВЭтойПрограмме);
		ВерсияВДругойПрограммеБезНомераСборки = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(ВерсияВДругойПрограмме);
		
		Если ВерсияВЭтойПрограммеБезНомераСборки <> ВерсияВДругойПрограммеБезНомераСборки Тогда
			
			СинонимПланаОбмена = Метаданные.ПланыОбмена[ИмяПланаОбмена].Синоним;
			
			ШаблонСообщения = НСтр("ru = 'Синхронизация данных может быть выполнена некорректно, т.к. версия программы ""%1"" (%2) в правилах конвертации этой программы отличается от версии %3 в правилах конвертации в другой программе. Убедитесь, что загружены актуальные правила, подходящие для используемых версий обеих программ.'");
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, СинонимПланаОбмена, ВерсияВЭтойПрограммеБезНомераСборки, ВерсияВДругойПрограммеБезНомераСборки);
			
			ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, УровеньЖурналаРегистрации.Предупреждение,,, ТекстСообщения);
			
			Если ПараметрыВнешнегоСоединения <> Неопределено
				И ОбщегоНазначенияКлиентСервер.СравнитьВерсии("2.2.3.18", ПараметрыВнешнегоСоединения.ВерсияБСППоВнешнемуСоединению) <= 0
				И ПараметрыВнешнегоСоединения.ВнешнееСоединение.ОбменДаннымиВнешнееСоединение.ПредупреждатьОНесоответствииВерсийПравилОбмена(ИмяПланаОбмена) Тогда
				
				СинонимПланаОбменаДругойПрограммы = ПараметрыВнешнегоСоединения.УзелИнформационнойБазы.Метаданные().Синоним;
				ТекстСообщенияВнешнееСоединение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения,
					СинонимПланаОбменаДругойПрограммы, ВерсияВДругойПрограммеБезНомераСборки, ВерсияВЭтойПрограммеБезНомераСборки);
				
				ПараметрыВнешнегоСоединения.ВнешнееСоединение.ЗаписьЖурналаРегистрации(ПараметрыВнешнегоСоединения.КлючСообщенияЖурналаРегистрации,
					ПараметрыВнешнегоСоединения.ВнешнееСоединение.УровеньЖурналаРегистрации.Предупреждение,,, ТекстСообщенияВнешнееСоединение);
				
			КонецЕсли;
			
			Если ПараметрыСеанса.ОшибкаРасхожденияВерсийПриПолученииДанных.ПроверятьРасхождениеВерсий Тогда
				
				СтруктураПроверки = Новый Структура(ПараметрыСеанса.ОшибкаРасхожденияВерсийПриПолученииДанных);
				СтруктураПроверки.ЕстьОшибка = Истина;
				СтруктураПроверки.ТекстОшибки = ТекстСообщения;
				СтруктураПроверки.ПроверятьРасхождениеВерсий = Ложь;
				ПараметрыСеанса.ОшибкаРасхожденияВерсийПриПолученииДанных = Новый ФиксированнаяСтруктура(СтруктураПроверки);
				Возврат Истина;
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция ИнициализироватьПараметрыПроверкиРасхожденияВерсий(ПроверятьРасхождениеВерсий) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	СтруктураПроверки = Новый Структура(ПараметрыСеанса.ОшибкаРасхожденияВерсийПриПолученииДанных);
	СтруктураПроверки.ПроверятьРасхождениеВерсий = ПроверятьРасхождениеВерсий;
	СтруктураПроверки.ЕстьОшибка = Ложь;
	ПараметрыСеанса.ОшибкаРасхожденияВерсийПриПолученииДанных = Новый ФиксированнаяСтруктура(СтруктураПроверки);
	
	Возврат ПараметрыСеанса.ОшибкаРасхожденияВерсийПриПолученииДанных;
	
КонецФункции

Функция ОшибкаРасхожденияВерсийПриПолученииДанных() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат ПараметрыСеанса.ОшибкаРасхожденияВерсийПриПолученииДанных;
	
КонецФункции

Функция ВерсияКорреспондентаВПравилах(ИмяПланаОбмена)
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	ПравилаДляОбменаДанными.ПравилаЗачитанныеКорреспондента,
	|	ПравилаДляОбменаДанными.ВидПравил
	|ИЗ
	|	РегистрСведений.ПравилаДляОбменаДанными КАК ПравилаДляОбменаДанными
	|ГДЕ
	|	ПравилаДляОбменаДанными.ИмяПланаОбмена = &ИмяПланаОбмена
	|	И ПравилаДляОбменаДанными.ПравилаЗагружены = ИСТИНА
	|	И ПравилаДляОбменаДанными.ВидПравил = ЗНАЧЕНИЕ(Перечисление.ВидыПравилДляОбменаДанными.ПравилаКонвертацииОбъектов)";
	
	Запрос.УстановитьПараметр("ИмяПланаОбмена", ИмяПланаОбмена);
	
	Результат = Запрос.Выполнить();
	
	Если Не Результат.Пустой() Тогда
		
		Выборка = Результат.Выбрать();
		Выборка.Следующий();
		
		СтруктураПравил = Выборка.ПравилаЗачитанныеКорреспондента.Получить().Конвертация;
		ВерсияКорреспондента = Неопределено;
		СтруктураПравил.Свойство("ВерсияКонфигурацииИсточника", ВерсияКорреспондента);
		
		Возврат ВерсияКорреспондента;
		
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Возвращает расширенное представление объекта.
//
Функция ПредставлениеОбъекта(ПараметрОбъект) Экспорт
	
	Если ПараметрОбъект = Неопределено Тогда
		Возврат "";
	КонецЕсли;
	МетаданныеОбъекта = ?(ТипЗнч(ПараметрОбъект) = Тип("Строка"), Метаданные.НайтиПоПолномуИмени(ПараметрОбъект), ПараметрОбъект);
	
	// Реквизитов представления может не быть, обходим через структуру.
	Представление = Новый Структура("РасширенноеПредставлениеОбъекта, ПредставлениеОбъекта");
	ЗаполнитьЗначенияСвойств(Представление, МетаданныеОбъекта);
	Если Не ПустаяСтрока(Представление.РасширенноеПредставлениеОбъекта) Тогда
		Возврат Представление.РасширенноеПредставлениеОбъекта;
	ИначеЕсли Не ПустаяСтрока(Представление.ПредставлениеОбъекта) Тогда
		Возврат Представление.ПредставлениеОбъекта;
	КонецЕсли;
	
	Возврат МетаданныеОбъекта.Представление();
КонецФункции

// Возвращает расширенное представление списка объектов.
//
Функция ПредставлениеСпискаОбъектов(ПараметрОбъект) Экспорт
	
	Если ПараметрОбъект = Неопределено Тогда
		Возврат "";
	КонецЕсли;
	МетаданныеОбъекта = ?(ТипЗнч(ПараметрОбъект) = Тип("Строка"), Метаданные.НайтиПоПолномуИмени(ПараметрОбъект), ПараметрОбъект);
	
	// Реквизитов представления может не быть, обходим через структуру.
	Представление = Новый Структура("РасширенноеПредставлениеСписка, ПредставлениеСписка");
	ЗаполнитьЗначенияСвойств(Представление, МетаданныеОбъекта);
	Если Не ПустаяСтрока(Представление.РасширенноеПредставлениеСписка) Тогда
		Возврат Представление.РасширенноеПредставлениеСписка;
	ИначеЕсли Не ПустаяСтрока(Представление.ПредставлениеСписка) Тогда
		Возврат Представление.ПредставлениеСписка;
	КонецЕсли;
	
	Возврат МетаданныеОбъекта.Представление();
КонецФункции

// Возвращает флаг доступности выгрузки для указанной ссылке на узле.
//
//  Параметры:
//      УзелОбмена             - ПланОбменаСсылка - узел плана обмена, возможность выгрузки по которому проверяется.
//      Ссылка                 - Произвольный     - проверяемый объект.
//      ДополнительныеСвойства - Структура        - дополнительные свойства, передаваемыми через объект.
//
// Возвращаемое значение:
//  Булево - флаг разрешения
//
Функция ВыгрузкаСсылкиРазрешена(УзелОбмена, Ссылка, ДополнительныеСвойства = Неопределено) Экспорт
	
	Если Ссылка.Пустая() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ОбъектРегистрации = Ссылка.ПолучитьОбъект();
	Если ОбъектРегистрации = Неопределено Тогда
		// Объект удален, можно всегда.
		Возврат Истина;
	КонецЕсли;
	
	Если ДополнительныеСвойства <> Неопределено Тогда
		СтруктураРеквизитов = Новый Структура("ДополнительныеСвойства");
		ЗаполнитьЗначенияСвойств(СтруктураРеквизитов, ОбъектРегистрации);
		ДополнительныеСвойстваОбъекта = СтруктураРеквизитов.ДополнительныеСвойства;
		
		Если ТипЗнч(ДополнительныеСвойстваОбъекта) = Тип("Структура") Тогда
			Для Каждого КлючЗначение Из ДополнительныеСвойства Цикл
				ДополнительныеСвойстваОбъекта.Вставить(КлючЗначение.Ключ, КлючЗначение.Значение);
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	// Проверка возможности выгрузки.
	Отправка = ОтправкаЭлементаДанных.Авто;
	ОбменДаннымиСобытия.ПриОтправкеДанныхКорреспонденту(ОбъектРегистрации, Отправка, , УзелОбмена);
	Возврат Отправка = ОтправкаЭлементаДанных.Авто;
КонецФункции

// Возвращает флаг доступности выгрузки вручную для указанной ссылке на узле.
//
//  Параметры:
//      УзелОбмена - ПланОбменаСсылка - узел плана обмена, возможность выгрузки по которому проверяется.
//      Ссылка     - Произвольный     -  проверяемый объект.
//
// Возвращаемое значение:
//  Булево - флаг разрешения
//
Функция ВыгрузкаСсылкиИзИнтерактивногоДополненияРазрешена(УзелОбмена, Ссылка) Экспорт
	
	// В случае вызова из схемы компоновки данных при работе механизма дополнения к выгрузке
	// включается безопасный режим, который нужно отключить на время выполнения этой функции.
	УстановитьОтключениеБезопасногоРежима(Истина);
	
	ДополнительныеСвойства = Новый Структура("ИнтерактивноеДополнениеВыгрузки", Истина);
	Возврат ВыгрузкаСсылкиРазрешена(УзелОбмена, Ссылка, ДополнительныеСвойства);
	
КонецФункции

// Обертки фоновых процедур интерактивного изменения выгрузки.
//
Процедура ИнтерактивноеИзменениеВыгрузки_СформироватьТабличныйДокументПользователя(Параметры, АдресРезультата) Экспорт
	
	ОбъектОтчета        = ИнтерактивноеИзменениеВыгрузки_ОбъектПоНастройкам(Параметры.СтруктураОбработки);
	РезультатВыполнения = ОбъектОтчета.СформироватьТабличныйДокументПользователя(Параметры.ПолноеИмяМетаданных, Параметры.Представление, Параметры.УпрощенныйРежим);
	ПоместитьВоВременноеХранилище(РезультатВыполнения, АдресРезультата);
	
КонецПроцедуры

Процедура ИнтерактивноеИзменениеВыгрузки_СформироватьДеревоЗначений(Параметры, АдресРезультата) Экспорт
	
	ОбъектОтчета = ИнтерактивноеИзменениеВыгрузки_ОбъектПоНастройкам(Параметры.СтруктураОбработки);
	Результат = ОбъектОтчета.СформироватьДеревоЗначений();
	ПоместитьВоВременноеХранилище(Результат, АдресРезультата);
	
КонецПроцедуры

// Параметры:
//   Настройки - Структура:
//     * НастройкиКомпоновщикаОтбораВсехДокументов - НастройкиКомпоновкиДанных
// 
Функция ИнтерактивноеИзменениеВыгрузки_ОбъектПоНастройкам(Знач Настройки)
	
	ОбъектОтчета = Обработки.ИнтерактивноеИзменениеВыгрузки.Создать();
	
	ЗаполнитьЗначенияСвойств(ОбъектОтчета, Настройки, , "КомпоновщикОтбораВсехДокументов");
	
	// Компоновщик конструируем по частям.
	Данные = ОбъектОтчета.КомпоновщикНастроекОбщегоОтбора();
	Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
	Компоновщик.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(Данные.СхемаКомпоновки));
	Компоновщик.ЗагрузитьНастройки(Данные.Настройки);
	
	ОбъектОтчета.КомпоновщикОтбораВсехДокументов = Компоновщик;
	
	ЭлементыОтбора = ОбъектОтчета.КомпоновщикОтбораВсехДокументов.Настройки.Отбор.Элементы;
	ЭлементыОтбора.Очистить();
	ОбъектОтчета.ДобавитьЗначенияОтбораКомпоновки(
		ЭлементыОтбора, Настройки.НастройкиКомпоновщикаОтбораВсехДокументов.Отбор.Элементы);
	
	Возврат ОбъектОтчета;
КонецФункции

// Возвращает список ролей профиля групп доступа "Синхронизация данных с другими программами".
// 
Функция РолиПрофиляДоступаСинхронизацияДанныхСДругимиПрограммами()
	
	МассивРолей = Новый Массив;
	МассивРолей.Добавить("ВыполнениеСинхронизацииДанных");
	МассивРолей.Добавить("УдаленныйДоступБазоваяФункциональность");
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВерсионированиеОбъектов") Тогда
		
		МассивРолей.Добавить("ЧтениеИнформацииОВерсияхОбъектов");
		
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДатыЗапретаИзменения")
		И Метаданные.Роли.Найти("ЧтениеДатЗапретаЗагрузки") <> Неопределено Тогда
		
		МассивРолей.Добавить("ЧтениеДатЗапретаЗагрузки");
		
	КонецЕсли;
	
	Возврат СтрСоединить(МассивРолей, ", ");
	
КонецФункции

// См. ТекущиеДелаПереопределяемый.ПриОпределенииОбработчиковТекущихДел
Процедура ПриЗаполненииСпискаТекущихДелНеобходимоОбновление(ТекущиеДела)
	
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	Если Не ПравоДоступа("Администрирование", Метаданные)
		Или МодульТекущиеДелаСервер.ДелоОтключено("НеобходимоОбновлениеОбменДанными") Тогда
		Возврат;
	КонецЕсли;
	
	ТребуетсяУстановкаОбновления = ТребуетсяУстановкаОбновления();
	
	// Процедура вызывается только при наличии подсистемы "Текущие дела", поэтому здесь
	// не делается проверка существования подсистемы.
	Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта(Метаданные.ОбщиеФормы.НастройкиСинхронизацииДанных.ПолноеИмя());
	
	Для Каждого Раздел Из Разделы Цикл
		
		ИдентификаторНеобходимоОбновление = "НеобходимоОбновлениеОбменДанными" + СтрЗаменить(Раздел.ПолноеИмя(), ".", "");
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор  = ИдентификаторНеобходимоОбновление;
		Дело.ЕстьДела       = ТребуетсяУстановкаОбновления;
		Дело.Важное         = Истина;
		Дело.Представление  = НСтр("ru = 'Обновить версию программы'");
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбновлениеКонфигурации") Тогда
			МодульОбновлениеКонфигурации = ОбщегоНазначения.ОбщийМодуль("ОбновлениеКонфигурации");
			ПараметрыФормы = Новый Структура("ЗавершениеРаботыСистемы, ПолученоОбновлениеКонфигурации", Ложь, Ложь);
			Дело.Форма      = МодульОбновлениеКонфигурации.ИмяФормыУстановкиОбновления();
			Дело.ПараметрыФормы = ПараметрыФормы;
		Иначе
			Дело.Форма      = "ОбщаяФорма.ДополнительноеОписание";
			Дело.ПараметрыФормы = Новый Структура("Заголовок,ИмяМакета",
				НСтр("ru = 'Установка обновления'"), "ИнструкцияКакВыполнитьУстановкуОбновленияВручную");
		КонецЕсли;
		Дело.Владелец       = Раздел;
		
	КонецЦикла;
	
КонецПроцедуры

Функция СинонимДанныхСтрокиДереваСтатистики(СтрокаДерева, ТипИсточникаСтрокой) 
	
	Синоним = СтрокаДерева.Синоним;
	
	Фильтр = Новый Структура("ПолноеИмя, Синоним", СтрокаДерева.ПолноеИмя, Синоним);
	Существующие = СтрокаДерева.Владелец().Строки.НайтиСтроки(Фильтр, Истина);
	Количество   = Существующие.Количество();
	Если Количество = 0 Или (Количество = 1 И Существующие[0] = СтрокаДерева) Тогда
		// Не было еще такого описания в этом дереве.
		Возврат Синоним;
	КонецЕсли;
	
	Синоним = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = '%1 (%2)'"),
		СтрокаДерева.Синоним,
		УдалитьИмяКлассаИзИмениОбъекта(ТипИсточникаСтрокой));
	
	Возврат Синоним;
КонецФункции

// Возвращаемое значение:
//   ТаблицаЗначений - коллекция регистров с движениями по заданному регистратору:
//     * ИмяТаблицыРегистра - Строка - полное имя таблицы регистра.
//     * НаборЗаписей - РегистрСведенийНаборЗаписей
//                    - РегистрНакопленияНаборЗаписей
//                    - и т.п. - набор записей.
//     * БезусловноеУдаление - Булево - признак безусловного удаления записей.
//
Функция ОпределитьНаличиеДвиженийПоДокументу(ДокументСсылка)
	
	МетаданныеДокумента = ДокументСсылка.Метаданные();
	Если МетаданныеДокумента.Движения.Количество() = 0 Тогда
		Результат = Новый ТаблицаЗначений;
		Результат.Колонки.Добавить("ИмяТаблицыРегистра", Новый ОписаниеТипов("Строка"));
		Результат.Колонки.Добавить("НаборЗаписей");
		Результат.Колонки.Добавить("БезусловноеУдаление", Новый ОписаниеТипов("Булево"));
		
		Возврат Результат;
	КонецЕсли;
	
	ТекстЗапроса = "";
	// Для исключения падения для документов, проводящимся более чем по 256 таблицам.
	СчетчикТаблиц = 0;
	
	ШаблонТекстаЗапроса = 
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	ВЫРАЗИТЬ(""&ИмяТаблицыМетаданных"" КАК СТРОКА(200)) КАК ИмяТаблицыРегистра
	|ИЗ
	|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных
	|ГДЕ
	|	ПсевдонимТаблицыМетаданных.Регистратор = &Регистратор";
	
	Для Каждого Движение Из МетаданныеДокумента.Движения Цикл
		// В запросе получаем имена регистров, по которым есть хотя бы одно движение.
		// Например,
		// ВЫБРАТЬ Первые 1 "РегистрНакопления.ТоварыНаСкладах"
		// ИЗ РегистрНакопления.ТоварыНаСкладах
		// ГДЕ Регистратор = &Регистратор.
		// Имя регистра приводим к Строка(200)
		
		Если НЕ ПустаяСтрока(ТекстЗапроса) Тогда
			
			ТекстЗапроса = ТекстЗапроса + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС;
			
		КонецЕсли;
		
		ТекстПодзапроса = СтрЗаменить(ШаблонТекстаЗапроса, "&ИмяТаблицыМетаданных", Движение.ПолноеИмя());
		ТекстЗапроса = ТекстЗапроса + ТекстПодзапроса;
		
		// Если в запрос попадает более 256 таблиц - разбиваем его на две части
		// (вариант документа с проведением по 512 регистрам считаем нежизненным).
		СчетчикТаблиц = СчетчикТаблиц + 1;
		Если СчетчикТаблиц = 256 Тогда
			
			Прервать;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Регистратор", ДокументСсылка);
	// При выгрузке для колонки "Имя" тип устанавливается по самой длинной строке из запроса
	// при втором проходе по таблице новое имя может не «влезть», по этому сразу в запросе
	// приводится к строка(200).
	ТаблицаЗапроса = Запрос.Выполнить().Выгрузить();
	ТаблицаЗапроса.Колонки.Добавить("НаборЗаписей");
	ТаблицаЗапроса.Колонки.Добавить("БезусловноеУдаление", Новый ОписаниеТипов("Булево"));
	
	// Если количество таблиц не превысило 256 - возвращаем таблицу.
	Если СчетчикТаблиц = МетаданныеДокумента.Движения.Количество() Тогда
		
		Возврат ТаблицаЗапроса;
		
	КонецЕсли;
	
	// Таблиц больше чем 256, делаем доп. запрос и дополняем строки таблицы.	
	ТекстЗапроса = "";
	Для Каждого Движение Из МетаданныеДокумента.Движения Цикл
		
		Если СчетчикТаблиц > 0 Тогда
			
			СчетчикТаблиц = СчетчикТаблиц - 1;
			Продолжить;
			
		КонецЕсли;
		
		Если НЕ ПустаяСтрока(ТекстЗапроса) Тогда
			
			ТекстЗапроса = ТекстЗапроса + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС;
			
		КонецЕсли;
		
		ТекстПодзапроса = СтрЗаменить(ШаблонТекстаЗапроса, "&ИмяТаблицыМетаданных", Движение.ПолноеИмя());
		ТекстЗапроса = ТекстЗапроса + ТекстПодзапроса;
		
	КонецЦикла;
	
	Запрос.Текст = ТекстЗапроса;
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		
		СтрокаТаблицы = ТаблицаЗапроса.Добавить();
		ЗаполнитьЗначенияСвойств(СтрокаТаблицы, Выборка);
		
	КонецЦикла;
	
	Возврат ТаблицаЗапроса;
	
КонецФункции

// Получает дерево метаданных конфигурации с заданным отбором по объектам метаданных.
//
// Параметры:
//   Отбор - Структура - содержит значения элементов отбора.
//						Если параметр задан, то будет получено дерево метаданных в соответствии с заданным отбором:
//            Ключ - Строка - имя свойства элемента метаданных;
//            Значение - Массив - множество значений для отбора.
//
// Пример инициализации переменной "Отбор":
//
// Массив = Новый Массив;
// Массив.Добавить("Константа.ИспользоватьСинхронизациюДанных");
// Массив.Добавить("Справочник.Валюты");
// Массив.Добавить("Справочник._ДемоОрганизации");
// Отбор = Новый Структура;
// Отбор.Вставить("ПолноеИмя", Массив);
// 
// Возвращаемое значение:
//   ДеревоЗначений - дерево описания метаданных конфигурации.
//
Функция ДеревоМетаданныхКонфигурации(Отбор = Неопределено) Экспорт
	
	ИспользоватьОтбор = (Отбор <> Неопределено);
	
	КоллекцииОбъектовМетаданных = Новый ТаблицаЗначений;
	КоллекцииОбъектовМетаданных.Колонки.Добавить("Имя");
	КоллекцииОбъектовМетаданных.Колонки.Добавить("Синоним");
	КоллекцииОбъектовМетаданных.Колонки.Добавить("Картинка");
	КоллекцииОбъектовМетаданных.Колонки.Добавить("КартинкаОбъекта");
	
	НоваяСтрокаКоллекцииОбъектовМетаданных("Константы",               НСтр("ru = 'Константы'"),                 БиблиотекаКартинок.Константа,              БиблиотекаКартинок.Константа,                    КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("Справочники",             НСтр("ru = 'Справочники'"),               БиблиотекаКартинок.Справочник,             БиблиотекаКартинок.Справочник,                   КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("Документы",               НСтр("ru = 'Документы'"),                 БиблиотекаКартинок.Документ,               БиблиотекаКартинок.ДокументОбъект,               КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("ПланыВидовХарактеристик", НСтр("ru = 'Планы видов характеристик'"), БиблиотекаКартинок.ПланВидовХарактеристик, БиблиотекаКартинок.ПланВидовХарактеристикОбъект, КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("ПланыСчетов",             НСтр("ru = 'Планы счетов'"),              БиблиотекаКартинок.ПланСчетов,             БиблиотекаКартинок.ПланСчетовОбъект,             КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("ПланыВидовРасчета",       НСтр("ru = 'Планы видов расчета'"),       БиблиотекаКартинок.ПланВидовРасчета,       БиблиотекаКартинок.ПланВидовРасчетаОбъект,       КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("РегистрыСведений",        НСтр("ru = 'Регистры сведений'"),         БиблиотекаКартинок.РегистрСведений,        БиблиотекаКартинок.РегистрСведений,              КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("РегистрыНакопления",      НСтр("ru = 'Регистры накопления'"),       БиблиотекаКартинок.РегистрНакопления,      БиблиотекаКартинок.РегистрНакопления,            КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("РегистрыБухгалтерии",     НСтр("ru = 'Регистры бухгалтерии'"),      БиблиотекаКартинок.РегистрБухгалтерии,     БиблиотекаКартинок.РегистрБухгалтерии,           КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("РегистрыРасчета",         НСтр("ru = 'Регистры расчета'"),          БиблиотекаКартинок.РегистрРасчета,         БиблиотекаКартинок.РегистрРасчета,               КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("БизнесПроцессы",          НСтр("ru = 'Бизнес-процессы'"),           БиблиотекаКартинок.БизнесПроцесс,          БиблиотекаКартинок.БизнесПроцессОбъект,          КоллекцииОбъектовМетаданных);
	НоваяСтрокаКоллекцииОбъектовМетаданных("Задачи",                  НСтр("ru = 'Задачи'"),                    БиблиотекаКартинок.Задача,                 БиблиотекаКартинок.ЗадачаОбъект,                 КоллекцииОбъектовМетаданных);
	
	// Возвращаемое значение функции.
	ДеревоМетаданных = Новый ДеревоЗначений;
	ДеревоМетаданных.Колонки.Добавить("Имя");
	ДеревоМетаданных.Колонки.Добавить("ПолноеИмя");
	ДеревоМетаданных.Колонки.Добавить("Синоним");
	ДеревоМетаданных.Колонки.Добавить("Картинка");
	
	Для Каждого СтрокаКоллекции Из КоллекцииОбъектовМетаданных Цикл
		
		СтрокаДерева = ДеревоМетаданных.Строки.Добавить();
		ЗаполнитьЗначенияСвойств(СтрокаДерева, СтрокаКоллекции);
		Для Каждого ОбъектМетаданных Из Метаданные[СтрокаКоллекции.Имя] Цикл
			
			Если ИспользоватьОтбор Тогда
				
				ОбъектПрошелФильтр = Истина;
				Для Каждого ЭлементОтбора Из Отбор Цикл
					
					Значение = ?(ВРег(ЭлементОтбора.Ключ) = ВРег("ПолноеИмя"), ОбъектМетаданных.ПолноеИмя(), ОбъектМетаданных[ЭлементОтбора.Ключ]);
					Если ЭлементОтбора.Значение.Найти(Значение) = Неопределено Тогда
						ОбъектПрошелФильтр = Ложь;
						Прервать;
					КонецЕсли;
					
				КонецЦикла;
				
				Если Не ОбъектПрошелФильтр Тогда
					Продолжить;
				КонецЕсли;
				
			КонецЕсли;
			
			СтрокаДереваОМ = СтрокаДерева.Строки.Добавить();
			СтрокаДереваОМ.Имя       = ОбъектМетаданных.Имя;
			СтрокаДереваОМ.ПолноеИмя = ОбъектМетаданных.ПолноеИмя();
			СтрокаДереваОМ.Синоним   = ОбъектМетаданных.Синоним;
			СтрокаДереваОМ.Картинка  = СтрокаКоллекции.КартинкаОбъекта;
			
		КонецЦикла;
		
	КонецЦикла;
	
	// Удаляем строки без подчиненных элементов.
	Если ИспользоватьОтбор Тогда
		
		// Используем обратный порядок обхода дерева значений.
		КоличествоЭлементовКоллекции = ДеревоМетаданных.Строки.Количество();
		
		Для ОбратныйИндекс = 1 По КоличествоЭлементовКоллекции Цикл
			
			ТекущийИндекс = КоличествоЭлементовКоллекции - ОбратныйИндекс;
			СтрокаДерева = ДеревоМетаданных.Строки[ТекущийИндекс];
			Если СтрокаДерева.Строки.Количество() = 0 Тогда
				ДеревоМетаданных.Строки.Удалить(ТекущийИндекс);
			КонецЕсли;
			
		КонецЦикла;
	
	КонецЕсли;
	
	Возврат ДеревоМетаданных;
	
КонецФункции

Процедура НоваяСтрокаКоллекцииОбъектовМетаданных(Имя, Синоним, Картинка, КартинкаОбъекта, Таб)
	
	НоваяСтрока = Таб.Добавить();
	НоваяСтрока.Имя               = Имя;
	НоваяСтрока.Синоним           = Синоним;
	НоваяСтрока.Картинка          = Картинка;
	НоваяСтрока.КартинкаОбъекта   = КартинкаОбъекта;
	
КонецПроцедуры

Функция КодПредопределенногоУзлаПланаОбмена(ИмяПланаОбмена) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ЭтотУзел = ОбменДаннымиПовтИсп.ПолучитьЭтотУзелПланаОбмена(ИмяПланаОбмена);
	
	Возврат СокрЛП(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ЭтотУзел, "Код"));
	
КонецФункции

// Возвращает массив всех узлов для заданного плана обмена кроме предопределенного узла.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена как оно задано в конфигураторе.
// 
// Возвращаемое значение:
//  МассивУзлов - Массив - массив всех узлов для заданного плана обмена кроме предопределенного узла.
//
Функция УзлыПланаОбмена(ИмяПланаОбмена) Экспорт
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	ПланОбмена.Ссылка КАК Ссылка
	|ИЗ
	|	#ИмяТаблицыПланаОбмена КАК ПланОбмена
	|ГДЕ
	|	НЕ ПланОбмена.ЭтотУзел");
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ИмяТаблицыПланаОбмена", "ПланОбмена." + ИмяПланаОбмена);
	
	Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
	
КонецФункции

Функция ИмяКаталогаДляСопоставленияФайловаяИБ() Экспорт
	
	Возврат СтроковыеФункцииКлиентСервер.ПараметрыИзСтроки(СтрокаСоединенияИнформационнойБазы()).File 
		+ ПолучитьРазделительПути() + "TempMessageForDataMatching";
	
КонецФункции

Функция ПолноеИмяФайлаДляСопоставленияФайловаяИБ(ИмяФайла) Экспорт
										
	Возврат ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(ИмяКаталогаДляСопоставленияФайловаяИБ(), ИмяФайла);
	
КонецФункции

// Останавливает выполнение кода на заданное время.
// Метод продублирован из БТС, т.к. п/с может использоваться без указанной библиотеки.
//
// Параметры:
//  Секунд - Число - время ожидания в секундах.
//
Процедура Пауза(Секунд) Экспорт
	
	ТекущийСеансИнформационнойБазы = ПолучитьТекущийСеансИнформационнойБазы();
	ФоновоеЗадание = ТекущийСеансИнформационнойБазы.ПолучитьФоновоеЗадание();
	
	Если ФоновоеЗадание = Неопределено Тогда
		
		Параметры = Новый Массив;
		Параметры.Добавить(Секунд);
		ФоновоеЗадание = ФоновыеЗадания.Выполнить("ОбменДаннымиСервер.Пауза", Параметры);
		
	КонецЕсли;
		
	ФоновоеЗадание.ОжидатьЗавершенияВыполнения(Секунд);
	
КонецПроцедуры

#КонецОбласти

#Область ИнтерактивноеИзменениеВыгрузки_СлужебныеПроцедурыИФункции

// Инициализирует дополнение выгрузки для мастера пошагового обмена.
//
// Параметры:
//     УзелИнформационнойБазы - ПланОбменаСсылка                - ссылка на узел, для которого производится настройка.
//     АдресХранилищаФормы    - Строка
//                            - УникальныйИдентификатор - адрес сохранения между серверными вызовами.
//     ЕстьСценарийУзла       - Булево                          - флаг необходимости дополнительной настройки.
//
// Возвращаемое значение:
//   Структура - данные для дальнейшего оперирования дополнением выгрузки:
//     * УзелИнформационнойБазы - ПланОбменаСсылка - ссылка на узел, для которого производится настройка.
//     * ВариантВыгрузки - Число - текущий вариант выгрузки.
//     * ПериодОтбораВсехДокументов - СтандартныйПериод - период отбора документов. По умолчанию - прошлый месяц.
//     * АдресКомпоновщикаВсехДокументов - Строка - адрес компоновщика настроек для отбора документов.
//     * ДополнительнаяРегистрация - см. ОписаниеДополнительнойРегистрацииВариантаВыгрузки
//     * ПараметрыСценарияДополнения - см. ОписаниеСтандартныхВариантовДополненияВыгрузки
//     * АдресХранилищаФормы - УникальныйИдентификатор - уникальный идентификатор формы для временного хранилища.
//
Функция ИнтерактивноеИзменениеВыгрузки(Знач УзелИнформационнойБазы, Знач АдресХранилищаФормы, Знач ЕстьСценарийУзла = Неопределено) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Результат = Новый Структура;
	Результат.Вставить("УзелИнформационнойБазы", УзелИнформационнойБазы);
	Результат.Вставить("ВариантВыгрузки",        0);
	
	Результат.Вставить("ПериодОтбораВсехДокументов", Новый СтандартныйПериод);
	Результат.ПериодОтбораВсехДокументов.Вариант = ВариантСтандартногоПериода.ПрошлыйМесяц;
	
	ОбработкаДополнения = Обработки.ИнтерактивноеИзменениеВыгрузки.Создать();
	ОбработкаДополнения.УзелИнформационнойБазы = УзелИнформационнойБазы;
	ОбработкаДополнения.ВариантВыгрузки        = 0;
	
	// Компоновщик собираем по частям.
	Данные = ОбработкаДополнения.КомпоновщикНастроекОбщегоОтбора(АдресХранилищаФормы);
	Результат.Вставить("АдресКомпоновщикаВсехДокументов", ПоместитьВоВременноеХранилище(Данные, АдресХранилищаФормы));
	
	Результат.Вставить("ДополнительнаяРегистрация", ОписаниеДополнительнойРегистрацииВариантаВыгрузки());

	Результат.Вставить("ПараметрыСценарияДополнения", ОписаниеСтандартныхВариантовДополненияВыгрузки());
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
	
	Если ЕстьСценарийУзла = Неопределено Тогда
		// Можно определить по метаданным узла.
		ЕстьСценарийУзла = Ложь;
	КонецЕсли;
	
	Если ЕстьСценарийУзла
		И ЕстьАлгоритмМенеджераПланаОбмена("НастроитьИнтерактивнуюВыгрузку", ИмяПланаОбмена) Тогда
		МодульМенеджераУзла = ПланыОбмена[ИмяПланаОбмена];
		МодульМенеджераУзла.НастроитьИнтерактивнуюВыгрузку(УзелИнформационнойБазы, Результат.ПараметрыСценарияДополнения);
	КонецЕсли;
	
	Результат.Вставить("АдресХранилищаФормы", АдресХранилищаФормы);
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//   ТаблицаЗначений - содержит строки с описанием подробных отборов по сценарию узла:
//     * ПолноеИмяМетаданных - Строка - полное имя метаданных регистрируемого объекта, отбор которого описывает строка.
//                                      Например "Документ._ДемоПоступлениеТоваров". Можно
//                                      использовать специальные  значения "ВсеДокументы" и
//                                      "ВсеСправочники" для отбора соответственно всех
//                                      документов и всех справочников, регистрирующихся на узле "Получатель".
//     * Отбор - ОтборКомпоновкиДанных - отбор по умолчанию. Поля отбора формируются в соответствии с общим
//                                       правилами формирования полей компоновки. Например, для указания
//                                       отбора по реквизиту документа "Организация", необходимо
//                                       использовать поле "Ссылка.Организация".
//     * Период - СтандартныйПериод - значение периода общего отбора для метаданных строки, предлагаемого по умолчанию.
//     * ВыборПериода - Булево - признак того, что данная строка описывает отбор с общим периодом.
//     * Представление - Строка - представление отбора.
//     * ОтборСтрокой - Строка - значение отбора в виде строки.
//     * Количество - Строка - количество элементов в отборе.
//
Функция ОписаниеДополнительнойРегистрацииВариантаВыгрузки()
	
	ДополнительнаяРегистрация = Новый ТаблицаЗначений;
	
	ДополнительнаяРегистрация.Колонки.Добавить("ПолноеИмяМетаданных", Новый ОписаниеТипов("Строка"));
	ДополнительнаяРегистрация.Колонки.Добавить("Отбор",               Новый ОписаниеТипов("ОтборКомпоновкиДанных"));
	ДополнительнаяРегистрация.Колонки.Добавить("Период",              Новый ОписаниеТипов("СтандартныйПериод"));
	ДополнительнаяРегистрация.Колонки.Добавить("ВыборПериода",        Новый ОписаниеТипов("Булево"));
	ДополнительнаяРегистрация.Колонки.Добавить("Представление",       Новый ОписаниеТипов("Строка"));
	ДополнительнаяРегистрация.Колонки.Добавить("ОтборСтрокой",        Новый ОписаниеТипов("Строка"));
	ДополнительнаяРегистрация.Колонки.Добавить("Количество",          Новый ОписаниеТипов("Строка"));
	
	Возврат ДополнительнаяРегистрация;
	
КонецФункции

// Возвращаемое значение:
//   Структура - настройки типового варианта дополнения выгрузки "Не добавлять":
//     * Использование - Булево - признак разрешения использования варианта. По умолчанию Истина.
//     * Порядок - Число - порядок размещения варианта на форме помощника, сверху вниз. По умолчанию 1.
//     * Заголовок - Строка - позволяет переопределить название типового варианта.
//     * Пояснение - Строка - позволяет переопределить текст пояснения варианта для пользователя.
//
Функция ОписаниеСтандартногоВариантаБезДополнения()
	
	Результат = Новый Структура;
	Результат.Вставить("Использование", Истина);
	Результат.Вставить("Порядок",       1);
	Результат.Вставить("Заголовок",     "");
	Результат.Вставить("Пояснение",     НСтр("ru = 'Будут отправлены только данные согласно общим настройкам.'"));
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//   Структура - настройки типового варианта дополнения выгрузки "Добавить все документы за период":
//     * Использование - Булево - признак разрешения использования варианта. По умолчанию Истина.
//     * Порядок - Число - порядок размещения варианта на форме помощника, сверху вниз. По умолчанию 2.
//     * Заголовок - Строка - позволяет переопределить название типового варианта.
//     * Пояснение - Строка - позволяет переопределить текст пояснения варианта для пользователя.
//
Функция ОписаниеСтандартногоВариантаВсеДокументы()
	
	Результат = Новый Структура;
	Результат.Вставить("Использование", Истина);
	Результат.Вставить("Порядок",       2);
	Результат.Вставить("Заголовок",     "");
	Результат.Вставить("Пояснение",     НСтр("ru = 'Дополнительно будут отправлены все документы за период, удовлетворяющие условиям отбора.'"));
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//   Структура - настройки типового варианта дополнения выгрузки "Добавить данные с произвольным отбором":
//     * Использование - Булево - признак разрешения использования варианта. По умолчанию Истина.
//     * Порядок - Число - порядок размещения варианта на форме помощника, сверху вниз. По умолчанию 3.
//     * Заголовок - Строка - позволяет переопределить название типового варианта.
//     * Пояснение - Строка - позволяет переопределить текст пояснения варианта для пользователя.
//
Функция ОписаниеСтандартногоВариантаПроизвольныйОтбор()
	
	Результат = Новый Структура;
	Результат.Вставить("Использование", Истина);
	Результат.Вставить("Порядок",       3);
	Результат.Вставить("Заголовок",     "");
	Результат.Вставить("Пояснение",     НСтр("ru = 'Дополнительно будут отправлены данные согласно отбору.'"));
	
	Возврат Результат;
	
КонецФункции

// Структура описания стандартного варианта дополнения выгрузки "ВариантДополнительно".
//
// Возвращаемое значение:
//   Структура - настройки типового варианта дополнения выгрузки по сценарию узла:
//     * Использование - Булево - признак разрешения использования варианта. По умолчанию Ложь.
//     * Порядок - Число - порядок размещения варианта на форме помощника, сверху вниз. По умолчанию 4.
//     * Заголовок - Строка - позволяет переопределить название типового варианта.
//     * Пояснение - Строка - позволяет переопределить текст пояснения варианта для пользователя.
//     * ИспользоватьПериодОтбора - Булево - признак того, что необходим общий отбор по периоду. По умолчанию Ложь.
//     * ПериодОтбора - СтандартныйПериод - значение периода общего отбора, предлагаемого по умолчанию.
//     * ИмяФормыОтбора - Строка - имя формы, вызываемой для редактирования настроек.
//     * ЗаголовокКомандыФормы - Строка - заголовок для отрисовки на форме команды открытия формы настроек.
//     * Отбор - см. ОписаниеДополнительнойРегистрацииВариантаВыгрузки
//
Функция ОписаниеСтандартногоВариантаДополнительно()
	
	Результат = Новый Структура;
	Результат.Вставить("Использование", Ложь);
	Результат.Вставить("Порядок",       4);
	Результат.Вставить("Заголовок",     "");
	Результат.Вставить("Пояснение",     НСтр("ru = 'Дополнительно будут отправлены данные согласно отбору.'"));
	
	Результат.Вставить("ИспользоватьПериодОтбора", Ложь);
	Результат.Вставить("ПериодОтбора",             Новый СтандартныйПериод);
	Результат.Вставить("ИмяФормыОтбора",           "");
	Результат.Вставить("ЗаголовокКомандыФормы",    "");
	Результат.Вставить("Отбор",                    ОписаниеДополнительнойРегистрацииВариантаВыгрузки());
	
	Возврат Результат;
	
КонецФункции

// Очистка отбора всех документов.
//
// Параметры:
//     ДополнениеВыгрузки - Структура
//                        - ДанныеФормыСтруктура - описание параметров выгрузки:
//       * КомпоновщикОтбораВсехДокументов - КомпоновщикНастроекКомпоновкиДанных
//       * АдресКомпоновщикаВсехДокументов - Строка
//       * АдресХранилищаФормы - Строка
//
Процедура ИнтерактивноеИзменениеВыгрузкиОчисткаОбщегоОтбора(ДополнениеВыгрузки) Экспорт
	
	Если ПустаяСтрока(ДополнениеВыгрузки.АдресКомпоновщикаВсехДокументов) Тогда
		ДополнениеВыгрузки.КомпоновщикОтбораВсехДокументов.Настройки.Отбор.Элементы.Очистить();
	Иначе
		Данные = ПолучитьИзВременногоХранилища(ДополнениеВыгрузки.АдресКомпоновщикаВсехДокументов); // КомпоновщикНастроекКомпоновкиДанных
		Данные.Настройки.Отбор.Элементы.Очистить();
		ДополнениеВыгрузки.АдресКомпоновщикаВсехДокументов = ПоместитьВоВременноеХранилище(Данные, ДополнениеВыгрузки.АдресХранилищаФормы);
		
		Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
		Компоновщик.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(Данные.СхемаКомпоновки));
		Компоновщик.ЗагрузитьНастройки(Данные.Настройки);
		ДополнениеВыгрузки.КомпоновщикОтбораВсехДокументов = Компоновщик;
	КонецЕсли;
	
КонецПроцедуры

// Очистка детального отбора
//
// Параметры:
//     ДополнениеВыгрузки - Структура
//                        - РеквизитФормыКоллекция - описание параметров выгрузки.
//
Процедура ИнтерактивноеИзменениеВыгрузкиОчисткаДетально(ДополнениеВыгрузки) Экспорт
	ДополнениеВыгрузки.ДополнительнаяРегистрация.Очистить();
КонецПроцедуры

// Определяет описание общего отбора. При пустом отборе возвращает пустую строку.
//
// Параметры:
//     ДополнениеВыгрузки - Структура
//                        - РеквизитФормыКоллекция - описание параметров выгрузки.
//
// Возвращаемое значение:
//     Строка - описание отбора.
//
Функция ИнтерактивноеИзменениеВыгрузкиОписаниеДополненияОбщегоОтбора(Знач ДополнениеВыгрузки) Экспорт
	
	ДанныеКомпоновщика = ПолучитьИзВременногоХранилища(ДополнениеВыгрузки.АдресКомпоновщикаВсехДокументов);
	
	Источник = Новый ИсточникДоступныхНастроекКомпоновкиДанных(ДанныеКомпоновщика.СхемаКомпоновки);
	Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
	Компоновщик.Инициализировать(Источник);
	Компоновщик.ЗагрузитьНастройки(ДанныеКомпоновщика.Настройки);
	
	Возврат ПредставлениеОтбораДополненияВыгрузки(Неопределено, Компоновщик, "");
КонецФункции

// Определяет описание детального отбора. При пустом отборе возвращает пустую строку.
//
// Параметры:
//     ДополнениеВыгрузки - Структура
//                        - РеквизитФормыКоллекция - описание параметров выгрузки.
//
// Возвращаемое значение:
//     Строка - описание отбора.
//
Функция ИнтерактивноеИзменениеВыгрузкиОписаниеДетальногоОтбора(Знач ДополнениеВыгрузки) Экспорт
	Возврат ПредставлениеДетальногоДополненияВыгрузки(ДополнениеВыгрузки.ДополнительнаяРегистрация, "");
КонецФункции

// Анализирует историю настроек-отборов, сохраненную пользователем для узла.
//
// Параметры:
//     ДополнениеВыгрузки - Структура
//                        - РеквизитФормыКоллекция - описание параметров выгрузки.
//
// Возвращаемое значение:
//     Список значений, где представление - имя настройки, значение - данные настройки.
//
Функция ИнтерактивноеИзменениеВыгрузкиИсторияНастроек(Знач ДополнениеВыгрузки) Экспорт
	ОбработкаДополнения = Обработки.ИнтерактивноеИзменениеВыгрузки.Создать();
	
	ФильтрВарианта = ИнтерактивноеИзменениеВыгрузкиФильтрВарианта(ДополнениеВыгрузки);
	
	Возврат ОбработкаДополнения.ПрочитатьПредставленияСпискаНастроек(ДополнениеВыгрузки.УзелИнформационнойБазы, ФильтрВарианта);
КонецФункции

// Восстанавливает настройки в реквизитах ДополнениеВыгрузки по названию сохраненной настройки.
//
// Параметры:
//     ДополнениеВыгрузки     - Структура
//                            - РеквизитФормыКоллекция - описание параметров выгрузки.
//     ПредставлениеНастройки - Строка                            - название восстанавливаемой настройки.
//
// Возвращаемое значение:
//     Булево - Истина - успешно восстановлено, Ложь - настройка не найдена.
//
Функция ИнтерактивноеИзменениеВыгрузкиВосстановитьНастройки(ДополнениеВыгрузки, Знач ПредставлениеНастройки) Экспорт
	
	ОбработкаДополнения = Обработки.ИнтерактивноеИзменениеВыгрузки.Создать();
	ЗаполнитьЗначенияСвойств(ОбработкаДополнения, ДополнениеВыгрузки);
	
	ФильтрВарианта = ИнтерактивноеИзменениеВыгрузкиФильтрВарианта(ДополнениеВыгрузки);
	
	// Восстанавливаем состояние объекта.
	Результат = ОбработкаДополнения.ВосстановитьТекущееИзНастроек(ПредставлениеНастройки, ФильтрВарианта, ДополнениеВыгрузки.АдресХранилищаФормы);
	
	Если Результат Тогда
		ЗаполнитьЗначенияСвойств(ДополнениеВыгрузки, ОбработкаДополнения, "ВариантВыгрузки, ПериодОтбораВсехДокументов, КомпоновщикОтбораВсехДокументов");
		
		// Обновляем адрес компоновщика всегда.
		Данные = ОбработкаДополнения.КомпоновщикНастроекОбщегоОтбора();
		Данные.Настройки = ДополнениеВыгрузки.КомпоновщикОтбораВсехДокументов.Настройки;
		ДополнениеВыгрузки.АдресКомпоновщикаВсехДокументов = ПоместитьВоВременноеХранилище(Данные, ДополнениеВыгрузки.АдресХранилищаФормы);
		
		ЗаполнитьТаблицуЗначений(ДополнениеВыгрузки.ДополнительнаяРегистрация, ОбработкаДополнения.ДополнительнаяРегистрация);
		
		// Настройки по сценарию узла обновляем только если они определены в прочитанном. Иначе оставляем текущее.
		Если ОбработкаДополнения.ДополнительнаяРегистрацияСценарияУзла.Количество() > 0 Тогда
			ЗаполнитьЗначенияСвойств(ДополнениеВыгрузки, ОбработкаДополнения, "ПериодОтбораСценарияУзла, ПредставлениеОтбораСценарияУзла");
			ЗаполнитьТаблицуЗначений(ДополнениеВыгрузки.ДополнительнаяРегистрацияСценарияУзла, ОбработкаДополнения.ДополнительнаяРегистрацияСценарияУзла);
			// Нормализуем установки периода.
			ИнтерактивноеИзменениеВыгрузкиУстановитьПериодаСценарияУзла(ДополнениеВыгрузки);
		КонецЕсли;
		
		// Текущее представление ранее запомненных настроек.
		ДополнениеВыгрузки.ПредставлениеТекущейНастройки = ПредставлениеНастройки;
	КонецЕсли;

	Возврат Результат;
КонецФункции

// Заполняет реквизит формы по данным структуры настроек.
//
// Параметры:
//     Форма                       - ФормаКлиентскогоПриложения - форма для установки реквизита.
//     НастройкиДополненияВыгрузки - см. ИнтерактивноеИзменениеВыгрузки
//     ИмяРеквизитаДополнения      - Строка - имя реквизита формы для создания или заполнения.
//
Процедура ИнтерактивноеИзменениеВыгрузкиРеквизитПоНастройкам(Форма, Знач НастройкиДополненияВыгрузки, Знач ИмяРеквизитаДополнения="ДополнениеВыгрузки") Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ПараметрыСценарияДополнения = НастройкиДополненияВыгрузки.ПараметрыСценарияДополнения;
	
	// Разбираемся с реквизитами
	РеквизитДополнения = Неопределено;
	КоллекцияРеквизитов = Форма.ПолучитьРеквизиты(); // Массив из РеквизитФормы
	Для Каждого Реквизит Из КоллекцияРеквизитов Цикл
		Если Реквизит.Имя = ИмяРеквизитаДополнения Тогда
			РеквизитДополнения = Реквизит;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	// Проверяем и добавляем реквизит.
	Добавляемые = Новый Массив;
	Если РеквизитДополнения=Неопределено Тогда
		РеквизитДополнения = Новый РеквизитФормы(ИмяРеквизитаДополнения, 
			Новый ОписаниеТипов("ОбработкаОбъект.ИнтерактивноеИзменениеВыгрузки"));
			
		Добавляемые.Добавить(РеквизитДополнения);
		Форма.ИзменитьРеквизиты(Добавляемые);
	КонецЕсли;
	
	// Проверяем и добавляем колонки общей дополнительной регистрации.
	ПутьРеквизитаТаблицы = РеквизитДополнения.Имя + ".ДополнительнаяРегистрация";
	Если Форма.ПолучитьРеквизиты(ПутьРеквизитаТаблицы).Количество()=0 Тогда
		Добавляемые.Очистить();
		Колонки = НастройкиДополненияВыгрузки.ДополнительнаяРегистрация.Колонки;
		Для Каждого Колонка Из Колонки Цикл
			Добавляемые.Добавить(Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, ПутьРеквизитаТаблицы));
		КонецЦикла;
		Форма.ИзменитьРеквизиты(Добавляемые);
	КонецЕсли;
	
	// Проверяем и добавляем колонки дополнительной регистрации сценария узла.
	ПутьРеквизитаТаблицы = РеквизитДополнения.Имя + ".ДополнительнаяРегистрацияСценарияУзла";
	Если Форма.ПолучитьРеквизиты(ПутьРеквизитаТаблицы).Количество() = 0 Тогда
		Добавляемые.Очистить();
		
		Колонки = ПараметрыСценарияДополнения.ВариантДополнительно.Отбор.Колонки;
		
		Для Каждого Колонка Из Колонки Цикл
			Добавляемые.Добавить(Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, ПутьРеквизитаТаблицы));
		КонецЦикла;
		Форма.ИзменитьРеквизиты(Добавляемые);
	КонецЕсли;
	
	// Добавляем данные
	ЗначениеРеквизита = Форма[ИмяРеквизитаДополнения];
	
	// Обрабатываем таблицы значений.
	ЗначениеВДанныеФормы(ПараметрыСценарияДополнения.ВариантДополнительно.Отбор,
		ЗначениеРеквизита.ДополнительнаяРегистрацияСценарияУзла);
	
	ПараметрыСценарияДополнения.ВариантДополнительно.Отбор = ТаблицаВМассивСтруктур(
		ПараметрыСценарияДополнения.ВариантДополнительно.Отбор);
	
	ЗначениеРеквизита.ПараметрыСценарияДополнения = ПараметрыСценарияДополнения;
	
	ЗначениеРеквизита.УзелИнформационнойБазы = НастройкиДополненияВыгрузки.УзелИнформационнойБазы;

	ЗначениеРеквизита.ВариантВыгрузки                 = НастройкиДополненияВыгрузки.ВариантВыгрузки;
	ЗначениеРеквизита.ПериодОтбораВсехДокументов      = НастройкиДополненияВыгрузки.ПериодОтбораВсехДокументов;
	
	Данные = ПолучитьИзВременногоХранилища(НастройкиДополненияВыгрузки.АдресКомпоновщикаВсехДокументов);
	УдалитьИзВременногоХранилища(НастройкиДополненияВыгрузки.АдресКомпоновщикаВсехДокументов);
	ЗначениеРеквизита.АдресКомпоновщикаВсехДокументов = ПоместитьВоВременноеХранилище(Данные, Форма.УникальныйИдентификатор);
	
	ЗначениеРеквизита.ПериодОтбораСценарияУзла = ПараметрыСценарияДополнения.ВариантДополнительно.ПериодОтбора;
	
	Если ПараметрыСценарияДополнения.ВариантДополнительно.Использование Тогда
		ЗначениеРеквизита.ПредставлениеОтбораСценарияУзла = ПредставлениеДополненияВыгрузкиПоСценариюУзла(ЗначениеРеквизита);
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры

// Возвращает описание выгрузки по настройкам.
//
// Параметры:
//     ДополнениеВыгрузки - Структура
//                        - ДанныеФормыКоллекция - описание параметров выгрузки:
//       * УзелИнформационнойБазы - ПланОбменаСсылка - узел плана обмена.
//
// Возвращаемое значение:
//     Строка - представление.
// 
Функция ПредставлениеДополненияВыгрузкиПоСценариюУзла(Знач ДополнениеВыгрузки)
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(ДополнениеВыгрузки.УзелИнформационнойБазы);
	
	Если Не ЕстьАлгоритмМенеджераПланаОбмена("ПредставлениеОтбораИнтерактивнойВыгрузки", ИмяПланаОбмена) Тогда
		Возврат "";
	КонецЕсли;
	МодульМенеджера = ПланыОбмена[ИмяПланаОбмена];
	
	Параметры = Новый Структура;
	Параметры.Вставить("ИспользоватьПериодОтбора", ДополнениеВыгрузки.ПараметрыСценарияДополнения.ВариантДополнительно.ИспользоватьПериодОтбора);
	Параметры.Вставить("ПериодОтбора",             ДополнениеВыгрузки.ПериодОтбораСценарияУзла);
	Параметры.Вставить("Отбор",                    ДополнениеВыгрузки.ДополнительнаяРегистрацияСценарияУзла);
	
	Возврат МодульМенеджера.ПредставлениеОтбораИнтерактивнойВыгрузки(ДополнениеВыгрузки.УзелИнформационнойБазы, Параметры);
КонецФункции

// Возвращает описание периода и отбора строкой.
//
//  Параметры:
//      Период:                период для описания отбора.
//      Отбор:                 отбор компоновки данных для описания.
//      ОписаниеПустогоОтбора: значение, возвращаемое в случае пустого отбора.
//
//  Возвращаемое значение:
//      Строка - описание периода и отбора.
//
Функция ПредставлениеОтбораДополненияВыгрузки(Знач Период, Знач Отбор, Знач ОписаниеПустогоОтбора=Неопределено) Экспорт
	
	НашОтбор = ?(ТипЗнч(Отбор)=Тип("КомпоновщикНастроекКомпоновкиДанных"), Отбор.Настройки.Отбор, Отбор);
	
	ПериодСтрокой = ?(ЗначениеЗаполнено(Период), Строка(Период), "");
	ОтборСтрокой  = Строка(НашОтбор);
	
	Если ПустаяСтрока(ОтборСтрокой) Тогда
		Если ОписаниеПустогоОтбора=Неопределено Тогда
			ОтборСтрокой = НСтр("ru='Все объекты'");
		Иначе
			ОтборСтрокой = ОписаниеПустогоОтбора;
		КонецЕсли;
	КонецЕсли;
	
	Если Не ПустаяСтрока(ПериодСтрокой) Тогда
		ОтборСтрокой =  ПериодСтрокой + ", " + ОтборСтрокой;
	КонецЕсли;
	
	Возврат ОтборСтрокой;
КонецФункции

// Возвращает описание детального отбора по реквизиту "ДополнительнаяРегистрация".
//
//  Параметры:
//      ДополнительнаяРегистрация - ТаблицаЗначений
//                                - Массив - строки или структуры, описывающие отбор.
//      ОписаниеПустогоОтбора     - Строка                  - значение, возвращаемое в случае пустого отбора.
//
Функция ПредставлениеДетальногоДополненияВыгрузки(Знач ДополнительнаяРегистрация, Знач ОписаниеПустогоОтбора=Неопределено) Экспорт
	
	Текст = "";
	Для Каждого Строка Из ДополнительнаяРегистрация Цикл
		Текст = Текст + Символы.ПС + Строка.Представление + ": " + ПредставлениеОтбораДополненияВыгрузки(Строка.Период, Строка.Отбор);
	КонецЦикла;
	
	Если Не ПустаяСтрока(Текст) Тогда
		Возврат СокрЛП(Текст);
		
	ИначеЕсли ОписаниеПустогоОтбора=Неопределено Тогда
		Возврат НСтр("ru='Дополнительные данные не выбраны'");
		
	КонецЕсли;
	
	Возврат ОписаниеПустогоОтбора;
КонецФункции

// Идентификатор служебной группы объектов метаданных "Все документы".
//
Функция ДополнениеВыгрузкиИдентификаторВсехДокументов() Экспорт
	// Не должно пересекаться с полным именем метаданных.
	Возврат "ВсеДокументы";
КонецФункции

// Идентификатор служебной группы объектов метаданных "Все справочники".
//
Функция ДополнениеВыгрузкиИдентификаторВсехСправочников() Экспорт
	// Не должно пересекаться с полным именем метаданных.
	Возврат "ВсеСправочники";
КонецФункции

// Производит установку общего периода во все разрезы отбора.
//
// Параметры:
//     ДополнениеВыгрузки - Структура
//                        - ДанныеФормыКоллекция - описание параметров выгрузки.
//
Процедура ИнтерактивноеИзменениеВыгрузкиУстановитьПериодаСценарияУзла(ДополнениеВыгрузки) Экспорт
	Для Каждого Строка Из ДополнениеВыгрузки.ДополнительнаяРегистрацияСценарияУзла Цикл
		Строка.Период = ДополнениеВыгрузки.ПериодОтбораСценарияУзла;
	КонецЦикла;
	
	// И обновляем представление
	ДополнениеВыгрузки.ПредставлениеОтбораСценарияУзла = ПредставлениеДополненияВыгрузкиПоСценариюУзла(ДополнениеВыгрузки);
КонецПроцедуры

// Возвращает используемые варианты отбора по данным настроек.
//
// Параметры:
//     ДополнениеВыгрузки - Структура
//                        - ДанныеФормыКоллекция - описание параметров выгрузки.
//
// Возвращаемое значение:
//     Массив из Число - с номерами используемых вариантов: 
//               0 - без отбора, 1 - отбор всех документов, 2 - подробный, 3 - сценарий узла.
//
Функция ИнтерактивноеИзменениеВыгрузкиФильтрВарианта(Знач ДополнениеВыгрузки) Экспорт
	
	Результат = Новый Массив;
	
	ТестДанных = Новый Структура("ПараметрыСценарияДополнения");
	ЗаполнитьЗначенияСвойств(ТестДанных, ДополнениеВыгрузки);
	ПараметрыСценарияДополнения = ТестДанных.ПараметрыСценарияДополнения;
	Если ТипЗнч(ПараметрыСценарияДополнения)<>Тип("Структура") Тогда
		// Нет настроек, значения по умолчанию - все.
		Возврат Неопределено;
	КонецЕсли;
	
	Если ПараметрыСценарияДополнения.Свойство("ВариантБезДополнения") 
		И ПараметрыСценарияДополнения.ВариантБезДополнения.Использование Тогда
		Результат.Добавить(0);
	КонецЕсли;
	
	Если ПараметрыСценарияДополнения.Свойство("ВариантВсеДокументы")
		И ПараметрыСценарияДополнения.ВариантВсеДокументы.Использование Тогда
		Результат.Добавить(1);
	КонецЕсли;
	
	Если ПараметрыСценарияДополнения.Свойство("ВариантПроизвольныйОтбор")
		И ПараметрыСценарияДополнения.ВариантПроизвольныйОтбор.Использование Тогда
		Результат.Добавить(2);
	КонецЕсли;
	
	Если ПараметрыСценарияДополнения.Свойство("ВариантДополнительно")
		И ПараметрыСценарияДополнения.ВариантДополнительно.Использование Тогда
		Результат.Добавить(3);
	КонецЕсли;
	
	Если Результат.Количество() = 4 Тогда
		// Есть все варианты, убираем фильтр.
		Возврат Неопределено;
	КонецЕсли;

	Возврат Результат;
КонецФункции

#КонецОбласти

#Область Прочее_СлужебныеПроцедурыИФункции

Процедура НастроитьЭлементыФормыЗацикливания(Форма)
	
	Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
		Возврат;
	КонецЕсли;
	
	УзелСсылка = Форма.Объект.Ссылка;
	Элементы = Форма.Элементы;
	
	Если УзелСсылка.Пустая() 
		Или Не ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(УзелСсылка) Тогда		
		
		ОбщегоНазначенияКлиентСервер.УстановитьСвойствоЭлементаФормы(
			Элементы,
			"ФормаОбщаяКомандаОбъектыНезарегистрированныеПриЗацикливании",
			"Видимость",
			Ложь);
	
		Возврат;
		
	КонецЕсли;
	
	ОбщегоНазначенияКлиентСервер.УстановитьСвойствоЭлементаФормы(
		Элементы,
		"ФормаОбщаяКомандаОбъектыНезарегистрированныеПриЗацикливании",
		"ПоложениеВКоманднойПанели",
		ПоложениеКнопкиВКоманднойПанели.ВДополнительномПодменю);
	
	Если Не ОбменДаннымиКонтрольЗацикливания.УзелЗациклен(УзелСсылка) Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПанели = "Зацикливание";
	
	Группа = Элементы.Вставить(ИмяПанели, Тип("ГруппаФормы"), Неопределено, Форма.Элементы.ФормаКоманднаяПанель);
	Группа.Вид 			= ВидГруппыФормы.ОбычнаяГруппа;
	Группа.Группировка 	= ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
	Группа.ЦветФона 	= ЦветаСтиля.ЦветФонаПредупреждения;
	Группа.ОтображатьЗаголовок = Ложь;
	
	ДекорацияОтступ = Элементы.Добавить("Отступ" + ИмяПанели, Тип("ДекорацияФормы"), Группа);
	ДекорацияОтступ.Вид = ВидДекорацииФормы.Надпись;
	
	ДекорацияКартинка = Элементы.Добавить("Картинка" + ИмяПанели, Тип("ДекорацияФормы"), Группа);
	ДекорацияКартинка.Вид 		= ВидДекорацииФормы.Картинка;
	ДекорацияКартинка.Картинка 	= БиблиотекаКартинок.Информация;
	ДекорацияКартинка.Высота 	= 3;
	ДекорацияКартинка.Ширина 	= 5;
	ДекорацияКартинка.РазмерКартинки = РазмерКартинки.Пропорционально;

	ШаблонТекста = НСтр("ru = '<br>Обнаружено зацикливание синхронизаций. Для получения подробной информации перейдите по 
			  |<a href=ФормаЗацикливаниеСинхронизации>ссылке</a>.
			  |<br><br>
			  |<a href=ФормаОбъектыНезарегистрированныеПриЗацикливании>Объекты незарегистрированные при зацикливании</a>.'");

	ФДок = Новый ФорматированныйДокумент;
	ФДок.УстановитьHTML("<html>" + ШаблонТекста + "</html>", Новый Структура);
	
	ДекорацияНадпись = Элементы.Добавить("Надпись" + ИмяПанели, Тип("ДекорацияФормы"), Группа);
	ДекорацияНадпись.Вид 						= ВидДекорацииФормы.Надпись;
	ДекорацияНадпись.АвтоМаксимальнаяШирина 	= Ложь;
	ДекорацияНадпись.РастягиватьПоГоризонтали 	= Истина;
	ДекорацияНадпись.Заголовок 					= ФДок.ПолучитьФорматированнуюСтроку();
	ДекорацияНадпись.УстановитьДействие("ОбработкаНавигационнойСсылки", "Подключаемый_ОбработкаНавигационнойСсылки");
	
КонецПроцедуры

Процедура ОчиститьСписокОшибокПриВыгрузкеДанных(УзелИнформационнойБазы) Экспорт
	
	Если Не ЗначениеЗаполнено(УзелИнформационнойБазы) Тогда
		Возврат;
	КонецЕсли;
	
	РегистрыСведений.РезультатыОбменаДанными.ОчиститьПроблемыПриОтправке(УзелИнформационнойБазы);
	
КонецПроцедуры

Процедура ОчиститьСписокОшибокПриЗагрузкеДанных(УзелИнформационнойБазы) Экспорт
	
	Если Не ЗначениеЗаполнено(УзелИнформационнойБазы) Тогда
		Возврат;
	КонецЕсли;
	
	РегистрыСведений.РезультатыОбменаДанными.ОчиститьПроблемыПриПолучении(УзелИнформационнойБазы);
	
КонецПроцедуры

Функция ТипыИсключаемыеИзПроверкиУстраненияПроблемы() Экспорт
	
	Типы = Новый Массив;
	Типы.Добавить(Метаданные.Справочники.СценарииОбменовДанными);
	Типы.Добавить(Метаданные.Справочники.СеансыОбменовДанными);
	
	ОбменДаннымиПереопределяемый.ПриЗаполненииТиповИсключаемыхИзПроверкиУстраненияПроблемы(Типы);
	
	Возврат Типы;
	
КонецФункции

#КонецОбласти

#КонецОбласти